2014-02-10 50 views
2

我使用溫莎與ASP.NET MVC4和我已經寫了一個自定義RoleProvider圍繞遺留安全框架。我需要將連接字符串和文件路徑注入提供程序,以便我可以將這些提供給傳統框架,但是當我使用AuthorizeAttribute時,我意識到我不知道如何攔截提供程序的構造以便注入這些值。如何使用Windsor將依賴注入到自定義RoleProvider中?

如果它有助於包括代碼,我的角色提供有這種構造的:

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 s。

這可能嗎?還是我需要看看提供這些依賴關係的另一種方式?

+0

看看這個相關的問題:https://stackoverflow.com/questions/15410575/custom-membership-provider-and-unity-injection – Steven

+0

對不起,我真的不知道這是如何幫助我直接。它給了我實現我自己的'IDependencyResolver'的想法,這可能工作,我猜? – adhocgeek

+0

問題是,你不能在你的'CustomRoleProvider'上進行依賴注入(就像你無法使用成員提供者一樣),因爲它是基於某些XML配置創建該類型的.NET框架。所以訣竅是創建一個你用XML配置的外觀,它解析了容器中的'真實'提供者。這基本上是相關問題描述的內容。 – Steven

回答

1

我的研究結果:

  • Windsor(不像StructureMap)不有注入性到現有的對象
  • AuthorizeAttribute不調入直接RoleProvider實現,它調用的方法到Thread.CurrentPrincipal返回一個IPrincipal執行...
  • 基本上不可能提供解決RoleProviderAuthorizeAttribute,儘管你可以通過編寫自己的IFilterProvider(cf. 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年2月12日

我找到了另一種方式通過refelection替換角色類的供應商。所有您在Web配置文件需要的是<roleManager enabled="true" />並在CustomRoleProvider覆蓋Name返回"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類做它的初始化魔術(否則我們不得不設置大量的其他專用字段),並且我們需要替換集合,因爲Roles類的消費者調用該集合以查找適當的提供者。

但是,我不確定我是否一定會推薦這個,我不確定這是否完全夠用,但它似乎對我來說至今還在工作。

更新2014年2月20日

有不同的方式做到這一點不涉及神奇的反射 - 雖然這個博客帖子在談論MembershipProviderhttp://bugsquash.blogspot.co.uk/2010/11/windsor-managed-membershipproviders.html

,這是相當瑣碎改爲改爲RoleProvider的代碼。實質上,這是使用一種適配器模式,將實際角色提供者的解析度留給適配器。它確實涉及到使容器靜態化,並以一種服務定位器的方式使用它,但我認爲這是一個小小的折衷。

相關問題