Castle 多繼承選擇
很多時候,我們定義了一個介面,但是這個介面會有多種不同的,這時IOC建構函式注入的時候,就需要自動選擇對應的實現。
public interface ITestService {}
public class TestService : IService
{
public string test()
{
return "test"
}
}
public class TestService_New : ICalculatorService
{
public string test()
{
return "test new";
}
}
此時,我們大多數情況下,需要用TestService來實現ITestService,但是少部分情況下,需要用TestService_New實現ITestService。
解決方案一
IOC中只實現需要用到的類:
Component.For<ITestService>()
.ImplementedBy<TestService>()
如果在某些地方部署時,修改為
Component.For
.ImplementedBy
這樣每次部署的時候都需要修改程式碼,而且需要手寫的規則會越來越多。
解決方案二
參考了Castle的WIKI,發現了可以ServiceOverrides重寫實現:
Component.For<ITestService>()
.ImplementedBy<TestService>()
.Named("myservice.default"),
Component.For<ITestService>()
.ImplementedBy<TestService_New>()
.Named("myservice.new"),
Component.For<TestController>()
.ServiceOverrides(ServiceOverride.ForKey("myService").Eq("myservice.new"))
嘗試了一下,VS提示改方法已過世,建議使用Dependency.OnComponent代替。
Component.For
.DependsOn(Dependency.OnComponent<ITestService, TestService_New>())
修改程式碼之後,怎麼都不起作用。重新翻看官方WIKI,發現了IsDefault方法,當多個類實現同一個介面時,可以通過IsDefault來置為預設實現。
解決方案三
//先通過DefaultInterfaces載入正常實現
Classes.FromAssembly(assembly)
.IncludeNonPublicTypes()
.BasedOn<IApplicationService>()
.WithService.DefaultInterfaces()
.LifestyleTransient()
.Configure(c =>
{
c.Interceptors<ExceptionInterceptor, TransactionInterceptor>();
c.Named(c.Implementation.Name);
}),
//根據WEBCONFIG載入特殊實現,並設定為預設實現
Classes.FromAssembly(assembly)
.IncludeNonPublicTypes()
.BasedOn<IApplicationService>()
.WithService.Select((type, @base) =>
type.GetAllInterfaces()
.Where(i => type.Name.Contains(GetInterfaceNameFromConf(i))))
.LifestyleTransient()
.Configure(c =>
{
c.Interceptors<ExceptionInterceptor, TransactionInterceptor>().IsDefault()
.Named(c.Implementation.FullName + "_" + ConfigurationManager.AppSettings["City"]);
})
private string GetInterfaceNameFromConf(Type @interface)
{
var name = @interface.Name;
if ((name.Length > 1 && name[0] == 'I') && char.IsUpper(name[1]))
{
return name.Substring(1) + "_" + ConfigurationManager.AppSettings["City"];
}
return name;
}
OK,大功告成。