我正在使用Windsor和ASP.NET MVC4
,我在遗留安全框架周围编写了一个自定义RoleProvider
。我需要将一个连接字符串和文件路径注入到提供程序中,这样我就可以将它们提供给遗留框架,但是当我来使用AuthorizeAttribute
时,我意识到我不知道如何拦截构造提供者以注入这些值。
如果包含代码有帮助,我的角色提供者就有这种构造函数:
public class CustomRoleProvider : RoleProvider
{
public CustomRoleProvider(string connectionString, string logPath)
{
LegacySecurity.ConnectionString = connectionString;
LegacySecurity.LogPath = logPath;
}
[Method overrides go here...]
}
我的AppSettingsConvention
看起来像这样:
public class AppSettingsConvention : ISubDependencyResolver
{
public bool CanResolve(CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
return ConfigurationManager.AppSettings.AllKeys.Contains(dependency.DependencyKey)
&& TypeDescriptor.GetConverter(dependency.TargetType).CanConvertFrom(typeof (string));
}
public object Resolve(CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
return TypeDescriptor.GetConverter(dependency.TargetType)
.ConvertFrom(ConfigurationManager.AppSettings[dependency.DependencyKey]);
}
}
(最初来自这里:http://blog.ploeh.dk/2012/07/02/PrimitiveDependencies/)
我希望我能以某种方式替换其中一个服务,就像我将HttpControllerActivator
替换为使用ApiController
的依赖注入一样。
这可能吗?或者我是否需要查看另一种提供这些依赖关系的方法?
答案 0 :(得分:1)
我的研究结果:
Windsor
(与StructureMap
不同)不可以将属性注入现有对象AuthorizeAttribute
不直接调用RoleProvider实现,它调用Thread.CurrentPrincipal
,返回IPrincipal
实现... RoleProvider
提供已解决的AuthorizeAttribute
,即使您可以通过编写自己的IFilterProvider
实施方案来调用提供商之前获得解决方案(参见IFilterProvider and separation of concerns)我最终做的是在CustomRoleProvider
上提供一个设置连接字符串和日志路径的方法,然后在Application_Start
中设置它:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var provider = Roles.Provider as CustomRoleProvider;
if (provider != null) provider.Initialize(ConfigurationManager.AppSettings[ConnectionKey], ConfigurationManager.AppSettings[LogPathKey]);
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), _container.Resolve<IHttpControllerActivator>());
ControllerBuilder.Current.SetControllerFactory(_container.Resolve<IControllerFactory>());
}
可能有更好的方法可以做到这一点,但目前我采用了务实的解决方案。
更新2014-02-12
我找到了另一种通过refelection替换Roles类中的提供程序的方法。您在网络配置文件中只需要<roleManager enabled="true" />
并覆盖Name
中的CustomRoleProvider
以返回"CustomRoleProvider"
,然后在Application_Start
方法中添加以下内容:< / p>
if (!(Roles.Provider is CustomRoleProvider))
{
var rolesType = typeof (Roles);
var flags = BindingFlags.Static | BindingFlags.NonPublic;
var provider = _container.Resolve<CustomRoleProvider>();
rolesType.GetField("s_Provider", flags).SetValue(null, provider);
var providers = new RoleProviderCollection();
providers.Add(provider);
rolesType.GetField("s_Providers", flags).SetValue(null, providers);
}
对Roles.Provider
的调用迫使Roles
类进行初始化魔术(否则我们必须设置大量其他私有字段)并且我们需要替换该集合,因为Roles类会调用它来寻找合适的提供者。
但是,我不确定我是否一定会推荐这个,我不确定这是否足够,但到目前为止似乎对我有用。
更新2014-02-20
有一种不同的做法,不涉及魔法反思 - http://bugsquash.blogspot.co.uk/2010/11/windsor-managed-membershipproviders.html
虽然这篇博客文章讨论的是MembershipProvider
,但更改RoleProvider
的代码却相当简单。本质上,这是使用一种适配器模式,将实际角色提供程序的分辨率保留到适配器。它确实涉及使容器静态并以一种服务定位方式使用它,但我认为这是一个小小的权衡。
答案 1 :(得分:0)
古老的问题,但这在2019年的Asp.Net RoleProvider中对我来说很好。
在您的DI容器配置中
{
... Type registrations
GlobalConfiguration.Configuration.DependencyResolver =
new UnityDependencyResolver(container);
}
在您的RoleProvider中...
private IYourType _yourType;
public override void Initialize(string name, NameValueCollection config)
{
...
_yourType = GlobalConfiguration
.Configuration
.DependencyResolver
.GetService(typeof(IYourType)) as IYourType;