web-dev-qa-db-ja.com

WCFサービスリファレンスは独自のコントラクトインターフェイスを生成し、私のものを再利用しません

私の最初の質問なので、それが適切であることを願っています:

共有インターフェースアセンブリ -インターフェイスを持つ「共有」アセンブリがあります。これをIDocRepositoryと呼びましょう。 [ServiceContract]でマークされており、[OperationContract]でマークされたメソッドがいくつかあります。

WCF実装アセンブリ -2つのWCFサービスプロジェクトがあり、それぞれが共有アセンブリを参照し、それぞれがそのインターフェイスをWCFサービスとして実装しています。

消費者集会 -最後に、2つのWCFサービスのそれぞれを参照して、共有アセンブリも参照する「クライアント」プロジェクトがあります。

ただし、コンシューマアセンブリで生成されるサービス参照は、自動生成されたバージョンのインターフェイスから派生します。

public partial class ExampleClient : System.ServiceModel.ClientBase<SomeNamespace.ExampleSvcRef.IDocRepository>, SomeNamespace.ExampleSvcRef.IDocRepository {

私が期待したこと
代わりに、両方の参照が、定義したインターフェイスを自動的に継承し、コンシューマー/クライアントアセンブリも参照していることを期待していました。パラメータとリターンタイプに提供するクラスの再利用に似ていますが、サービスインターフェイス用です。

なぜ
いずれかのサービス参照プロキシのインスタンスを作成し、それを自分のインターフェイスタイプにキャストできるようにします。

したがって、生成されたコードを毎回手動で変更することはできますが、もっと良い方法があるはずです...?

(編集:両方のサービス参照に対して[参照されるアセンブリのタイプを再利用する]オプションと[参照されるすべてのアセンブリのタイプを再利用する]オプションが選択されています)

39

「参照されたアセンブリでの型の再利用」では、サービスコントラクトではなく、データコントラクトのみを再利用できます。サービスコントラクトを共有する場合は、「サービス参照の追加」を使用する必要はありません。 ChannelFactory を直接使用できます。

// Supply the binding and address in code
Binding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://tempuri.org/address");
IServiceContract channel = ChannelFactory<IServiceContract>.CreateChannel(binding, address);

// Or read them from the config file
ChannelFactory<IServiceContract> channelFactory = new ChannelFactory<IServiceContract>();
IServiceContract channel = channelFactory.CreateChannel();

チャネルオブジェクトは ICommunicationObject も実装するため、Open()やClose()などのメソッドを呼び出す必要がある場合はキャストできます。

46
Quartermeister

サービス参照を作成すると、共有定義を再利用するためのチェックボックスがあります。クライアントプロジェクトが共有アセンブリを既に参照していることを確認し、サービス参照を再度追加し、すべてのオプションを注意深く確認します。

それでも機能しない場合は、使用しているバインディングを確認してください。基本的なHTTPバインディングではタイプの再利用がサポートされないという漠然とした思い出がありますか?

4
David M

Visual Studioは、プロキシクラスを生成するときに既存のインターフェイスを再利用することをサポートしていません。 Quartermeisterが指摘したように、再利用タイプはコントラクトインターフェイスを再利用しません。

継承で解決しました。 Jester Softwareによって提案された上記の部分クラスのアイデアに非常に似ています。

これが私たちがそれを解決した方法です:

クライアントのプロジェクトで、サービス参照を作成するだけです。次に、クライアントの代わりとなるクラスを追加します。

internal class MyServiceProxy : MyServiceClient, MyLogicNamespace.IMyService
{}

このクラスは、生成されたMyServiceClientを継承しますが、そのクライアントが元のインターフェイスを実装していることを示します。

(「ServiceProxies」という名前のフォルダーに配置することをお勧めします)

MyServiceClientクラスに元のインターフェースと一致しないメソッドが含まれている場合は、それらをそのプロキシーに追加し、コードで変換を行うことができます。

この後、MyServiceClientを使用する場所でMyServiceProxyを使用するだけです。

3
Ron Deijkers

プロキシジェネレーターを使用し続けたいが、機能は限定されているがある程度有用である場合は、別の良いオプションがあります...部分クラスを使用します。

namespace <same namespace as generated proxy>
{
    public partial class MyClient : <namespace of "real" service contract>.IServiceContract
    {
    }
}

サービスコントラクトがコードを定義するのと同じ方法でプロキシがコードを生成していることを確認します。つまり、「リスト」を使用している場合は、サービス参照の設定でもそのオプションを使用します。つまり、生成されたサービスインターフェイスが実際のサービスインターフェイスと完全に同じであり、上記のコードが機能することを確認し、参照を更新するには、コードを記述する代わりに右クリックを使用します。

2
Jesse Anderson