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<TestService_New>()
这样每次部署的时候都需要修改代码,而且需要手写的规则会越来越多。
解决方案二
参考了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,大功告成。