2011-08-16 10 views
2

私は3つのアセンブリ、Example.Core、Example.Contracts、Example.WcfServicesを持っているとします。私の契約組立では、インターフェースを定義し、いくつかの操作を追加します。 ICalculatorは、操作Add(double a、double b)を持ちます。私のWcfServicesアセンブリでは、Wcfサービスとして実装されたICalculatorの実装があります。Wcfコントラクト用にインタフェースを代替使用する方法

今、私の質問は(私はインターフェイスの代替実装を持つことができるようにする)デカップリングのすべてを維持しながら、私はそのインターフェイスに対してプログラミングんどのように私Example.Coreアセンブリに....これです。 ICalculatorが必要なクラスがある場合、ChannelFactoryから作成して使用するか、コンストラクターにインスタンスを挿入できます。私がクラスで作成した場合、私はChannelFactory/Wcfのクラスに依存関係を置いています。本当にやりたくありません。コンストラクタにインスタンスを挿入すると、注入クラスはwcfサービスをどのように管理し整理しますか?私はインターフェイスを持っていますが、私はそれを使用するきれいな方法がないようです。私はNInjectのようなものを見てきましたが、もしそれが問題であれば、ChannelFactoryをきれいにするとは思っていません。(少なくとも、チャンネル上ではなくAbortを呼び出す時を知っていることを示す文書は見つかりませんでした。

私がやったことは、私のインターフェースをもう一度やり直し、この質問に記載されている方法を使用しています:creating WCF ChannelFactory<T>とサービスのメソッドを呼び出すだけです。これは、チャンネルが正しく閉じられ/中止されるように、すべての呼び出しを再度ラッピングするので、私にはちょっと匂いがします。

インターフェイスの2つの実装があり、そのうちの1つがWcfサービスであるパターン/メソッドは誰も持っていますか?

ありがとう、

マイク

+0

あなたはサービス側またはクライアント側について尋ねていますか? –

+0

私はクライアント側について疑問に思います。明確にするために、別のアセンブリでインターフェイスを作成し、複数の実装を使用すると、wcf実装のオブジェクトのライフタイムを管理するのが難しいため、実装をスワップするのが難しくなります。 –

+0

http://stackoverflow.com/questions/3010820/dependency-injection-wcf/3011473#3011473 –

答えて

5

回答linked in Mark's commentthis article hereのバリエーションを使用して、私にとって効果的な解決策を思いつきました。あなたが定義したサービス契約を考えると

、ステップ1はあなたのサービスとIClientChannelを実装するインターフェイスを定義することになります。

// Service Contract 
public interface ICalculator 
{ 
    Add(double a, double b); 
} 

// Interface to expose Close and Abort 
public interface ICalculatorChannel : ICalculator, IClientChannel { } 

ステップ2プロキシを作成し、接続を閉じるか、中止するコードを実装処理する再利用可能なコードを作成することを含みます。 ServiceClient<T>

public class ServiceClient<T> where T : class, IClientChannel 
{ 
    private ProxyGenerator _generator = new ProxyGenerator(); 

    public T CreateProxy(string endpointConfigurationName) 
    { 
     return _generator.CreateInterfaceProxyWithoutTarget<T> 
      (new WcfInterceptor<T>(endpointConfigurationName)); 
    } 
} 

T ProxyGenerator城プロジェクトの一部であり、ステップ1で定義ICalculatorChannelかかります。ここでの使用方法は、WCFサービスへの呼び出しをインターセプトし、前後のアクションを実行できるようにすることです。

public class WcfInterceptor<T> : IInterceptor where T : IClientChannel 
{ 
    private ChannelFactory<T> _factory = null; 

    public WcfInterceptor(string endpointConfigurationName) 
    { 
     _factory = new ChannelFactory<T>(endpointConfigurationName); 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     T channel = _factory.CreateChannel(); 

     try 
     { 
      invocation.ReturnValue = invocation.Method.Invoke 
       (channel, invocation.Arguments); 
     } 
     finally 
     { 
      closeChannel(channel); 
     } 
    } 
} 

ご覧のとおり、Interceptメソッドは、チャネルとチャネルを閉じるための呼び出しをカプセル化します。 closeChannelメソッドは、Close()またはAbort()を呼び出すという決定を処理します。

private void closeChannel(T channel) 
    { 
     if (channel != null) 
     { 
      try 
      { 
       if (channel.State != CommunicationState.Faulted) 
       { 
        channel.Close(); 
       } 
       else 
       { 
        channel.Abort(); 
       } 
      } 
      catch 
      { 
       channel.Abort(); 
      } 
     } 
    } 

ここで、このServiceClientの使用方法をまとめたクラスを作成します。

public class Calculator : ICalculator 
{ 
    private var _calcualtor = new ServiceClient<ICalculatorChannel>(); 

    public void Add(double a, double b) 
    { 
     var proxy = _calculator.CreateProxy("endpointConfigGoesHere"); 

     return proxy.Add(a, b); 
    } 
} 

addの実装は、もはやWCF接続の問題に対処する必要はありません。消費クラスは、サービス契約について知っているだけです。障害のある接続を扱うのは、今やServiceClientクラスで扱われています。

クライアントは、現在1つの依存関係のみを取る必要があります。

public class MyClient 
{ 
    private ICalculator _calculator; 

    public MyClient(ICalculator calculator) 
    { 
     _calculator = calculator; 
    } 
} 

そして、IOCは、クライアントを移入することができます

Bind<ICalculator>().To<Calculator>(); 
+0

ありがとうございました。あなたが説明したことは、私がやり遂げたルートとほぼ同じです。私はこの例で管理されているチャネルファクトリを使用しました。これは上記のように動作します。 http://stackoverflow.com/questions/3200197/creating-wcf-channelfactoryt –

関連する問題