Unity を使用して WCF サービス内から依存関係階層を構築し、アプリケーション内のすべてのアセンブリを完全に疎結合に保つ方法を示すことを目的とした POC を作成しています。
私がしたことは、次のクラス ライブラリを作成することです。
データ アクセス レイヤー:
- リポジトリ インターフェイスを備えた 1 つのアセンブリ。
- DB にアクセスするふりをするこのインターフェイスの実装を含む 1 つのアセンブリ。
- XML ドキュメントにアクセスするふりをするこのインターフェイスの実装を含む 1 つのアセンブリ。
ビジネス層:
- ビジネス オブジェクト インターフェイスを持つ 1 つのアセンブリ。
- コンストラクターでリポジトリ インターフェイスを受け取る、このインターフェイスの実装を含む 1 つのアセンブリ。
サービス層:
- サービス インターフェイスを持つ 1 つのアセンブリ。
- コンストラクターでビジネス オブジェクト インターフェイスを受け取る、このインターフェイスの実装を含む 1 つのアセンブリ。
最後に、サービス ホスト ファクトリ、サービス ホスト、および依存関係階層の作成を担当するインスタンス プロバイダーを含むアセンブリを作成しました。コードは次のようになります。
public class UnityServiceHostFactory : ServiceHostFactory
{
private readonly UnityContainer _container;
public UnityServiceHostFactory()
{
_container = new UnityContainer();
new ContainerConfigurator().Configure(_container);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new UnityServiceHost(_container, serviceType, baseAddresses);
}
}
public class ContainerConfigurator
{
public void Configure(UnityContainer container)
{
container.RegisterType<IInvoiceRepository, InvoiceRepository>("dbInvoiceRepository");
container.RegisterType<IInvoiceRepository, XmlInvoice>("xmlInvoiceRepository");
container.RegisterType<IInvoiceFinder, InvoiceFinder>();
}
}
public class UnityServiceHost : ServiceHost
{
public UnityServiceHost(UnityContainer container, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if(container == null) throw new ArgumentNullException("container");
var contracts = ImplementedContracts.Values;
foreach (var c in contracts)
{
var instanceProvider = new UnityInstanceProvider(container, serviceType);
c.Behaviors.Add(instanceProvider);
}
}
}
public class UnityInstanceProvider : IInstanceProvider, IContractBehavior
{
private readonly UnityContainer _container;
private readonly Type _serviceType;
public UnityInstanceProvider(UnityContainer container, Type serviceType)
{
if (container == null) throw new ArgumentNullException("container");
if (serviceType == null) throw new ArgumentNullException("serviceType");
_container = container;
_serviceType = serviceType;
}
public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return _container.Resolve(_serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
_container.Teardown(instance);
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = this;
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
}
これをコンソール アプリケーションでテストしています。サービス プロキシをインスタンス化し、そのメソッドを呼び出しますが、両方の登録に名前が付けられているため、Unity はどちらをインスタンス化するかわかりません。どちらかから名前を削除すると、正常に解決されます。
基本的には、次のようなことができるようにしたいと考えています。
static void Main(string[] args)
{
//First call, want it to resolve to the InvoiceRepository concrete type
//new InvoiceService(new InvoiceFinder(new InvoiceRepository))
var invoiceService1 = new InvoiceProxy();
var response1 = invoiceService1.GetSumarizedInvoiceBy(new InvoiceRequest(1));
//Second call, want it to resolve to the XmlInvoice concrete type
//new InvoiceService(new InvoiceFinder(new XmlInvoice))
var invoiceService2 = new InvoiceProxy();
var response2 = invoiceService2.GetSumarizedInvoiceBy(new InvoiceRequest(2));
}
請求書サービス 1 と請求書サービス 2 は同じサービスの 2 つの異なるインスタンスですが、独自の依存関係内の依存関係は両方で異なる方法で解決されていることに注意してください。
サービス プロキシをインスタンス化するか、そのメソッドを呼び出すときに、どのリポジトリをインスタンス化するかを Unity に指示するにはどうすればよいですか?
ご協力いただきありがとうございます。