我有两种实现IEmailService
,一种用于测试,一种用于实时(is-A)。我有一个BusinessService
参考IEmailService
。
BusinessService
IEmailService (has-A)
IEmailService
TestEmailService (is-A)
LiveEmailService (is-A)
在统一配置中,我注册了两个IEmailService
实现,如下所示。
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="DataAccess.IEmailService, DataAccess"
mapTo="DataAccess.LiveEmailService, DataAccess"
name="Live">
<lifetime type="singleton" />
</register>
<register type="DataAccess.IEmailService, DataAccess"
mapTo="DataAccess.TestEmailService, DataAccess"
name="Test">
<lifetime type="singleton" />
</register>
<container>
</unity>
基于appSetting
forIEmailService
我希望 Unity 选择正确的实现。这将有助于测试。
<appSettings>
<add key="IEmailService" value="Test"/>
</appSettings>
问题是当 unity 解决时BusinessService
,它会尝试解决(none)
命名映射IEmailService
而不是Live
orTest
并抛出ResolutionFailedException
.
container.Resolve<BusinessService>();
抛出以下异常:
BusinessServices.Test.BusinessServiceTest_Integration.Test103:
Microsoft.Practices.Unity.ResolutionFailedException : Resolution of the dependency failed, type = "BusinessServices.BusinessService", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, DataAccess.IEmailService, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:
Resolving BusinessServices.BusinessService,(none)
Resolving parameter "emailService" of constructor BusinessServices.BusinessService(DataAccess.IEmailService emailService)
Resolving DataAccess.IEmailService,(none)
----> System.InvalidOperationException : The current type, DataAccess.IEmailService, is an interface and cannot be constructed. Are you missing a type mapping?
我想出的解决方法是在代码中指定注册,并有一个包装方法来container.RegisterType
注册命名映射以及基于值。IEmailService
(none)
appSetting
IUnityContainer container;
// registering unity
static void Load()
{
container = new UnityContainer().LoadConfiguration();
RegisterType<IEmailService, TestEmailService>("Test");
RegisterType<IEmailService, LiveEmailService>("Live");
}
// register the `Test` or `Live` implementation with `(none)` named mapping as per appSetting
static void RegisterType<TFrom, TTo>(string name)
where TTo : TFrom
{
var tFromAppSetting= ConfigurationManager.AppSettings[typeof(TFrom).Name];
if (!string.IsNullOrEmpty(tFromAppSetting) && tFromAppSetting == name)
container.RegisterType<TFrom, TTo>();
}
这可行,但我最终在两个地方指定了注册 - 配置和代码。有没有更好的方法来做到这一点?
更新
我实际上已经通过代码得到了正确的结果。我根本不需要统一配置。根据值,将或实现RegisterType<TFrom, TTo>(string name)
注册为命名映射。也无一例外地解决了。Test
Live
(none)
appSetting
BusinessService
由于没有统一配置,我没有加载配置。
container = new UnityContainer();