c# - 如何使用 Windsor 将依赖项注入(inject)自定义 RoleProvider?

标签 c# asp.net-mvc-4 castle-windsor

我将 Windsor 与 ASP.NET MVC4 一起使用我写了一个自定义 RoleProvider围绕遗留安全框架。我需要将连接字符串和文件路径注入(inject)提供程序,以便我可以将它们提供给遗留框架,但是当我开始使用 AuthorizeAttribute 时,我意识到我不知道如何拦截提供者的构造以注入(inject)这些值。

如果包含代码有帮助,我的角色提供者有这种构造函数:

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 中使用依赖注入(inject)

这可能吗?或者我是否需要寻找另一种方式来提供这些依赖项?

最佳答案

我的研究结果:

  • Windsor (与 StructureMap 不同)没有将属性注入(inject)现有对象的方法
  • AuthorizeAttribute不直接调用 RoleProvider 实现,它调用 Thread.CurrentPrincipal返回 IPrincipal实现...
  • 基本上不可能提供已解决的 RoleProviderAuthorizeAttribute ,即使您可以通过编写自己的 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

我找到了另一种通过反射替换 Roles 类中的提供者的方法。您的 Web 配置文件中只需要 <roleManager enabled="true" />并覆盖 Name在你的CustomRoleProvider返回 "CustomRoleProvider"然后在 Application_Start方法添加这个:

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类来执行它的初始化魔法(否则我们必须设置大量其他私有(private)字段)并且我们需要替换集合,因为 Roles 类的消费者调用它来寻找合适的提供者。

但是,我不确定我是否一定会推荐这个,我不确定这是否完全足够,但到目前为止它似乎对我有用。

更新 2014-02-20

有一种不涉及魔法反射的不同方法 - http://bugsquash.blogspot.co.uk/2010/11/windsor-managed-membershipproviders.html

尽管这篇博文谈论的是 MembershipProvider , 更改 RoleProvider 的代码相当简单反而。本质上,这是使用一种适配器模式,将实际角色提供者的解析留给适配器。它确实涉及使容器静态化并以一种服务定位器的方式使用它,但我认为这是一个小的权衡。

关于c# - 如何使用 Windsor 将依赖项注入(inject)自定义 RoleProvider?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21682314/

相关文章:

c# - 无法调用服务引用?

caSTLe-windsor - 在 CaSTLe Windsor 容器中注册多个类型工厂

inversion-of-control - IoC 避免注入(inject)容器

c# - 序列化动态类型参数 Protobuf-net

c# - 有没有办法找出DateTime变量对应的日历?

c# - ViewModel 属性在 HttpPost 上保持为 null

c# - 网络表单和依赖注入(inject)

c# - 异步组件和 WinForms

c# - 尝试/最终阻止与调用处置?

asp.net - 如何找到对应值的枚举名称并在 DisplayFor 中使用它?