2011-05-03 97 views
3

我想了解如何使用Castle Windsor IoC,并且在理解如何配置某些对象时遇到一些困难我需要动态解析。基本上,我有几个IDataSource的实现,我需要根据如何配置特定的“数据源”来选择要使用的实现。所以我可能会将相当多的数据源配置为使用3种实现中的一种。我的期望是,依赖代码将依赖于一个工厂方法,当它提供了“数据源ID”以及数据源实现需要的依赖项(IPrincipal)时,将为它们提供正确的IDataSource。如何配置Castle Windsor根据提供给Resolve()的参数(除名称以外)动态选择提供程序

我正在努力如何正确书写温莎的注册代表。下面大概是我得到的。我试图使用DynamicParameters方法(可能不是正确的使用方法)执行逻辑,该逻辑计算出要使用哪种实现,然后调用Resolve来提取该特定版本。但我不知道如何返回已解决的对象,因为DynamicParameters预计为ComponentReleasingDelegate,我假设它应该是类似return k => { k.ReleaseComponent(dataSource); }的东西。但是,那么我如何让我获得的数据源返回到容器,以便它返回给调用者?

struct DataSourceInfo { 
    string Id; 
    string ProviderType; 
} 

interface ICatalog : IDictionary<string /* Id */, DataSourceInfo> { 
    /* ... */ 
} 

class Catalog : ICatalog { 
    /* implement dictionary which looks up DataSourceInfo from their string id */ 
} 

interface IDataSource { /* ... */ } 

class Source1 : IDataSource { 
    Source1(string id, IPrincipal principal) { /* ... */ } 
} 

class Source2 : IDataSource { 
    Source2(string id, IPrincipal principal) { /* ... */ } 
} 

/* ... */ 
/* ... inside Windsor configuration section */ 
container.Register(Component.For<ICatalog>().LifeStyle.Singleton.ImplementedBy<Catalog>()); 

// Default service provider is a factory method which uses the string (data source id) 
// and looks up the DataSourceInfo from the ICatalog. It then uses info.ProviderType 
// to request IoC to resolve that specific implementation and passes in "id" and "principal" 
// to be used to resolve the dependencies of the implementation 
container.Register(Component.For<IDataSource>().LifeStyle.Transient 
    .DynamicParameters((kernel, context, args) => { 
     if (args == null || !args.Contains("id") || !(args["id"] is string)) throw ApplicationException("bad args"); 

     var id = (string)args["id"]; 
     var catalog = kernel.Resolve<ICatalog>(); 
     DataSourceInfo info; 
     try { info = catalog[id]; } finally { kernel.ReleaseComponent(catalog); } 

     // Now resolve the actual IDataSource 
     var dataSource = kernel.Resolve<IDataSource>(info.ProviderType, args); 

     // How do I return dataSource??? 
    }); 

// Now register the actual implementations 
container.Register(Component.For<IDataSource>().LifeStyle.Transient.ImplementedBy<Source1>().Named("Source1")); 
container.Register(Component.For<IDataSource>().LifeStyle.Transient.ImplementedBy<Source2>().Named("Source2")); 

/* ... */ 
/* some application startup code which configures some data sources */ 
class AppConfigurer { 
    AppConfigurer(ICatalog catalog) { 
    catalog["sourceA"] = new DataSourceInfo() { Id = "sourceA", ProviderType = "Source1" }; // data sourceA is provided by Source1 class 
    catalog["sourceB"] = new DataSourceInfo() { Id = "sourceB", ProviderType = "Source2" }; // data sourceB is provided by Source2 class 
    catalog["sourceC"] = new DataSourceInfo() { Id = "sourceC", ProviderType = "Source2" }; // data sourceC is provided by Source2 class 
    catalog["sourceD"] = new DataSourceInfo() { Id = "sourceD", ProviderType = "Source2" }; // data sourceD is provided by Source2 class 
    catalog["sourceE"] = new DataSourceInfo() { Id = "sourceE", ProviderType = "Source1" }; // data sourceE is provided by Source1 class   
    } 
} 

// Here is where I actually want to use IDataSources, and I do not want to know all the business about IDataSourceInfo. I just know a dataSourceId and an IPrincipal and want to get an IDataSource to work with. 
class Dependant { 
    Dependant (Func<string, IPrincipal, IDataSource> factory) { 
    var sourceA = factory("sourceA", somePrincipal); // sourceA.GetType() == typeof(Source1) 
    var sourceB = factory("sourceB", somePrincipal); // sourceB.GetType() == typeof(Source2) 
    var sourceC = factory("sourceC", somePrincipal); // sourceC.GetType() == typeof(Source2) 
    } 
} 

编辑:切换从DynamicParametersUsingFactoryMethod我可以做我想做的。但我一直认为这是错误的,因为现在如果我做container.ResolveAll()我真的很喜欢它跳过工厂方法,但我不知道如何让它做到这一点。

回答