BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース WCFクライアントのより良い構築法

WCFクライアントのより良い構築法

原文(投稿日:2014/03/06)へのリンク

遠慮なしに言えば、Visual Studioがデフォルトで自動生成するWCFクライアントには問題がある。 生成されるコードがサーバー側のインタフェース・コードとぴったり一致しないという問題もあり、これが原因でコードやデータを共有する時に多くの問題を引き起こしていることもあるが、それを除いても、自動生成されるコードにはいまだに明白なバグがある。 Michael Taylorは、「もっと賢いWCFサービスクライアント」というタイトルの連載の中で、これらの問題とそれらの対処法=を説明している。

WCFクライアントプロキシの周知の問題の1つは、サーバーが実際に実行されない限り、それらを自動生成することができないことである。 このせいで、多くの開発チームにとっては、ビルド時にサービス参照を更新することが不可能ではないとしても困難なものになっている。 代わりに、変更があれば忘れずにお互いに通知しあい、必要に応じて手動でサービス参照を更新するという方法を取らざるを得ない。 Michaelは次のように続けている。

サービス参照を生成するために使用したURLは生成されたコード(.svcmap)に埋め込まれてしまう。 参照が更新されると、元のURLが使用される。 元のURLが古いか、開発者のマシンを参照していた場合に、これが問題となり得る。 さらに悪いことに、サービス参照を再生成するためにURLを変更すると、すべてのファイルが更新されてしまう。実際のコードには変更がない場合でもおかまいなしにである。

サービス参照スタイルのWCFクライアントを使用するときのよくある誤りは、「using」ブロックを使用することである。 この方法は一般的ではあるが適切ではない。なぜなら、WCFクライアントはDisposeが呼び出されたときに例外をスローする可能性があるためである。 これは、「WCFのDispose問題」として知られており、回避策も非常に一般的だ。

Michaelは次のような問題点も引用している。

  • WCFはインタフェースを使用して実装の詳細を隠蔽しているが、生成されたコードには実際には別のインターフェイスが含まれていて、それらが同じ名前を共有している。 そのインターフェースは、サービス参照コードに定義されている。 このせいで、複数のプロジェクトで元のインタフェースを使用することがより困難になっている。
  • さらに悪いことには、メソッドのシグネチャの一部は変更される可能性がある。 たとえば、列挙可能オブジェクトやコレクションはデフォルトでは配列に変換される。 パラメータは移動させられることすらある。
  • Visual Studioでは、「すべての参照の検索」を使って型やメンバーへの参照をすべて見つけることができる。 しかし、サービス参照を使用している場合は「すべての参照の検索」では検出できない。なぜなら、繰り返しになるが、サービス参照が別の新しいインターフェースを生成するからである。
  • サービス参照から引っ張り出されたデータコントラクトも同様に変更されている。 それらは、元=のオブジェクトにはないプロパティを含んでいる。繝 これらのプロパティを使用するコードがあった場合、WCFが提供するインフラストラクチャに依存する形となり、ユニットテストがさらに困難になる。
  • データを共有しようなんて考えてはいけない、そのデータがあるプロジェクトのサービス参照によって生成されているのであれば。そのようなデータは他のプロジェクトとは共有できない(もしそれが同じサービスだったとしても)。 型は、名前が同じだったとしてもコンパイラにとっては異なる。
  • WCFがインターフェイスを使用するそもそもの理由は抽象化のためだったはずだが、サービス参照の動作のせいで、実際にサービスの利用法を抽象化するのは全然簡単ではない。

Michaelがまず推奨しているのは、ClientBase<T>をサブクラス化してIDisposableパターンを正しく実装することだ。 彼はこう書いている。

このラッパーについて他に興味深い点は、それがIDisposableを実装していることだ。 ClientBase<T>は最初からこのインターフェースを実装しているのに、なぜ再実装する必要があるのだろうか?それは、この基底型は、当該インターフェイスを実装するための正しいやり方に従っていないからだ。 このインタフェースを実装する場合、クラスはオーバーライド可能なメソッドを提供し、派生クラスで実装できるようにすることが要求されるが、この型はそうしていない。 クリーンアップコードを修正するためには、このインターフェイスと実際のメソッドを再実装する必要がある。 それでも我々は、適切に実装するつもりだ。派生型の面でも、障害が発生したチャネルの処理の面でも、両方において。

現在進行中の連載のパート3でMichaelが語っているのは、個々のサービスの呼び出しを行うために必要なボイラープレートを1行にまで減らす方法についてである。 たとえば、このような形になる。

ServiceClientFactory.InvokeMethod<ServiceReference1.IEmployeeService>(c => c.Update(dlg.Employee));

このパターンは、独自の制約をいくつかもたらしてしまう。

上記のコードの最大の問題は、おそらく静的クラスに依存していることだろう。 静的クラスはテスト中にモックに置き換えることが簡単ではない。そのため、この静的クラスを使用するコードは、WCFサービスを利用せずにユニットテストをすることが簡単ではない。 この問題を回避するには、仮想メソッドを作成して、その中でこの静的クラスを呼び出すようにすればよいが、ユニットテストのためだけの仮想メソッドがたくさんできてしまうことになる(おそらく、各サービスメソッドに1つずつ)。

Michaelは、これらの問題を後の記事で解決する予定だ。

この記事に星をつける

おすすめ度
スタイル

BT