WCFのサービスにMEFを使って依存性注入
以下の記事を参考にしました。
この記事はMEFではなくPIABを使っていますが、好きなDIコンテナに置き換えて読めると思います。
簡単なサンプル
簡単なサンプルを作って実際に動かしてみました。
サービスコントラクトの実装
MEFがフックできるようにMefServiceBehavior属性がついているのがポイント。Import属性がついたプロパティはMEFによって設定されます。
[MefServiceBehavior]
public class Service1 : IService1
{
[Import]
public Greeting Greeting { get; set; }public string Hello()
{
return Greeting.Hello();
}
}
MEFによってエキスポートされるクラス
エキスポートされてサービスコントラクトの実装にインポートされます。
[Export(typeof(Greeting))]
public class Greeting
{
public string Hello()
{
return "Hello!!!";
}
}
Service1でGreetingインスタンスを呼び出したいわけですが、デフォルトのままではGreetingはServic1にImporされないので、そのために必要なクラスを以下に作ります。
サービスのインスタンスを提供するクラス。
WCFの拡張ポイント。
public class MefInstanceProvider : IInstanceProvider
{
public CompositionContainer Container { get; private set; }public MefInstanceProvider()
{
Container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
}public object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}public object GetInstance(InstanceContext instanceContext, Message message)
{
var type = instanceContext.Host.Description.ServiceType;
if (type == null)
{
throw new InvalidOperationException();
}
var instance = Activator.CreateInstance(type);
Container.SatisfyImportsOnce(instance);
return instance;
}public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
var disposable = instance as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
サービスコントラクトを制御する属性。
WCFの拡張ポイント。サービスコントラクトもしくはサービスコントラクトの実装クラスに指定できます。
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class)]
public class MefServiceBehavior : Attribute, IContractBehavior, IContractBehaviorAttribute
{
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = new MefInstanceProvider();
}public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}public Type TargetContract
{
get
{
return null;
}
}
}