IEmailService
テスト用とライブ用 (is-A) の2 つの実装があります。そしてBusinessService
、has-AIEmailService
参照があります。
BusinessService
IEmailService (has-A)
IEmailService
TestEmailService (is-A)
LiveEmailService (is-A)
Unity config では、次のように 2 つの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
forに基づいて、IEmailService
Unity に正しい実装を選択してもらいます。これは、テスト中に役立ちます。
<appSettings>
<add key="IEmailService" value="Test"/>
</appSettings>
問題は、ユニティが解決するときに、 orの代わりに の名前付きマッピングBusinessService
を解決しようとし、 をスローすることです。(none)
IEmailService
Live
Test
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>();
}
これは機能しますが、登録を 2 つの場所 (構成とコード) で指定することになります。これを行うためのより良い方法はありますか?
アップデート
私は実際にコードでそれを正しくしました。ユニティ構成はまったく必要ありません。は、値に応じてまたは実装を名前付きマッピングとしてRegisterType<TFrom, TTo>(string name)
登録します。も例外なく解決されます。Test
Live
(none)
appSetting
BusinessService
ユニティ構成がないため、構成をロードしていません。
container = new UnityContainer();