ものがたり(旧)

atsushieno.hatenablog.com に続く

Essential WCF日本語訳を読んだ

エッセンシャルWCF:Windows Communication Foundation (Programmer’s Selection―Microsoft .net Development Series)

エッセンシャルWCF:Windows Communication Foundation (Programmer’s Selection―Microsoft .net Development Series)

日本語でもWCF関係の書籍がそれなりに出てきたみたいだけど、新しいのが一冊翻訳されて出てきたので、早速読んでみた。で、ざっと眺め直しながら、読んでいて思ったことを書いていこうと思う。

基本的には、膨大なWCFのトピックの中で、ある程度トピックを絞り込んで、割と本質的な話から入り込んで、ある程度の深さまでは掘り下げてくれる類の解説書だと思う。初心者がfast pathで学習できるように取捨選択しつつ、慣れている人でもWCFの本質を押さえながら読めるように書かれている印象がある。IISとかCOM統合とかMSMQ辺りにはあまり入り込まないので、いかにもWindowsべったりのWCFの解説書とは趣を異にしていて好印象だ。

一方で、多少ミスリーディングな記述があったりするし、どのトピックもあまり深入りすることはないので、詳しく追求したい人には物足りないかもしれない。そういう人はProgramming WCF Servicesを読んだ方が良いと思う(日本語訳は無いけど)。

Programming Wcf Services

Programming Wcf Services

Essential WCFは、扱っているトピックとしても、他人に勧めやすい良書なのではないかと思う。無駄かなあと思うトピックはPNRPくらいだろうか。*1

割と本質的な話から入っていると感じられるのは、たとえば基本的にコードだけでIISとかconfigファイルとか使わないサンプルから入るあたりだ。IISの.svcファイルやweb|exe.configはほとんどブラックボックスで、最初からきちんと理解するのは無理なので*2、なるべく物事を理解しようとするプログラマにとっては、ServiceHostを使ってコードだけの世界から入る本書のやり方の方がつっかかるところが少ないのではないかと思う。まあすぐ.svcやconfigのやり方も(やり方だけ)説明するんだけど。

クライアント プロクシについても、いきなりsvcutilを使ったり、Visual StudioのAdd Service Reference機能を使ったりすることはせず、ChannelFactory<T>.CreateChannel()を使うところから説明する。こういう説明は、WCFの基本的な仕組みが分かっていなければ出来ない。CreateChannel()はcontractの実装プロクシを返すので、生成されたプロクシに深入りする必要もなく十分に実用的だ。

コントラクト」の章では、少しcontractの分類に疑問を覚える部分もあるが(たとえば引数と戻り値がMessageであるconrtact methodは「メッセージコントラクト」とは関係ない。message contractはフルにserializerが使われる領域だ)、必要十分な記述になっているのではないかと思う。

一方で、「チャネル」の章はたいへん記述が少ない。channel listenerについては記述が足りなすぎる。channel factoryについては、記述が足りなすぎるだけでなく、ChannelFactoryとChannelFactoryBaseが混同される(これについては、説明を書いたら長くなりすぎたので補論にまとめる)。しかしチャネルの章は一方でコラムにちょこちょことハマりどころのフォローアップが書かれているので(ChannelFactoryとusingの関係とか、クライアントのIChannelの再利用性とか)、ツボを押さえているような印象もある。

バインディング」の章は、ページ数だけは多いけど、System.ServiceModel.dllに入っているひと通りのBindingについていちいち説明しているので、内容は濃くない。Nicholas Allen's Indigo blogと同じような話しか書いていない*3。binding elementの説明も最後の方にあるけど、細かく分類している割には網羅的でないし(PeerCustomResolverBindingElementとか抜けている)、間違いがある(ピアトランスポートチャネルはPeerBindingElementではなくPeerTransportBindingElement)。

あとこの章で看過できないのは「Webサービスを使用して相互運用性を確保する場合は『ws』で始まるバインディングを使用すべき」などという記述だ。WSHttpBindingやその亜流bindingは、WS-*のbindingでしかないし、WSHttpBinding等で使用されるSecurityBindingElementがデフォルトで使用するcredential(WSHttpBinding.Securiy.Message.ClientCredentialType)はWindows認証(MessageCredentialType.Windows)だ。一体これのどこがinteroperableなのか。これを相互運用性があると主張するなら、せっかく「セキュリティ」の章で細かく説明してある証明書ベースの認証について言及しておくべきだ。

続く「ビヘイビア」の章も、それなりの量があるけど、ここは前章とは異なり膨大なI*Behaviorの実装のほとんどを説明せず、ほぼconcurrencyとtransactionに話を絞ってじっくり書かれている。ほとんどの人にとって重要なのはこの辺だろうから、良い絞り込み方だと思う。ただ、話を絞りすぎていて、IServiceBehavior, IEndpointBehavior, IContractBehavior, IOperationBehavior それと IExtension の違いくらい説明してあっても良いのではないかとは思う。「カスタムビヘイビア」のセクションでちょっとだけ説明されているけど、これじゃ何だか分からないだろう。behaviorは、使い方を教えるだけで終わってしまうものかもしれないけど、そのインターフェースメソッドの実装が何をしているかを知ることが出来た方が良いのだろうなと思う。*4

serializationにかかる章は、xmlリアライザ(XmlObjectSerializerおよびXmlSerializer)やMessageEncodingBindingElementの説明だけでなく、IDataContractSurrogateなども割とじっくり説明しているように見える。デフォルトシリアライゼーションについても言及しておくべきなんじゃないかとは思う*5。あと細かいことをいえば、「WCFには、バイナリ、テキスト、MTOM (Message Transmission Optimization Mechanism)、JavaScript Object Notation、およびPOX(Plain Old XML)という5種類のエンコード形式が用意されています。」って書いてあるけど(P.210)、テキストというのはTextMessageEncodingBindingElementのことで、POXというのはたぶんWebMessageEncodingBindingElementのXML形式のことだから、これらを区別するのは変だ。*6

ホスティング」の章は、長くはないけど、冒頭で飛ばされた「どの環境でもServiceHost(Base)は生成される」という説明が冒頭にあったりして、必要十分な説明になっているのではないかと思う。

「セキュリティ」の章は、細かく説明したら際限が無いので、WCFの文脈に絞って説明しているのはたぶん正解なんだと思う。他の本ではWS-SecurityとかWS-Trustの説明なんかが入ったりもするけど、その辺の説明はここでは一切なしで割り切っている。ただ、このレイヤの存在理由と言っても良いであろうCardSpaceへの言及くらいはあった方が良かったのではないか…w

あと「診断」と「例外処理」でそれぞれ章立てしてまとめてあるのはユーザに優しい。service trace viewerを使えるようになると、デバッグが一段と楽になることもある。

残る3章は特定のbindingの使い方(WFとContextBindingElement、NetPeerTcpBinding、WebHttpBinding)なので、ここでは言及しない(ContextBindingElementについては全く知らないし)。ちなみに、原書が2007年に出版されたもので、Astoriaや新しいものについては何も書かれていない。

最後に本書について特に強く主張したいことは無いのだけど、僕にとってはどちらかというとProgramming WCF Servicesの方が参考になる(これはこれで特定の領域にしか踏み込まないのだけど)。でも普通のWCFユーザはそこまで深入りしなくてもいいので、僕の印象を参考にしてはいけないと思うw

補論: channel listenerとchannel factoryについて

本書の「チャネル」の章でchannel listenerと言われているのはIChannelListenerだが、このインスタンスを生成するのはBinding.BuildChannelListener()で、これに対応するメソッドBinding.BuildChannelFactory()が返すのはIChannelFactoryであり、そのほとんどがChannelFactoryBaseであるにすぎない。ChannelFactoryBaseと、ChannelFactoryおよびChannelFactory<T>は全く別物だ。本書でChannelFactoryについて語っている部分を、サービスサイドについて語るなら、それはChannelDispatcherやEndpointDispatcherだ。

本書では「チャネルリスナとチャネルファクトリのひとつの大きな違いとして、チャネルファクトリが関連づけられているチャネルを全て終了するのに対して、チャネルリスナはチャネルを終了しません。」という記述があるが(P.91)、IChannelFactoryの実装やChannelFactoryBaseの派生クラスは全てのIChannelインスタンスを終了する必要はないし、ChannelFactory.OnClose()がチャネルを全て閉じるのと同様、ChannelDispatcherもチャネルは全て閉じる。

*1:P2PチャネルはIDuplexChannelの説明に使えばぴったりなのだけど、本書ではSystem.Net.Peer2Peerの説明に逸れてしまっている。

*2:.svcのIHttpHandlerだって内部的にはServiceHostBase使っているはずだし、configファイルは内部的にServiceModelSectionGroupとその枝葉のインスタンスになって、結局ServiceHostをコードで調整するのと変わらないのだけど、そんなこと知りようがない。

*3:indigo blogは長続きしていて量も充実しているけど、bindingについては簡単なプロパティの説明程度しかしていない

*4:あと、本書に限らず、大抵のcustom behaviorの実装例はI*MessageInspectorをいじるものに終始しているけど、読者はそこで初めてDispatchRuntimeやEndpointDispatcherに触れることになって「??」な状態になるような気がする。

*5:System.Net.IPAddress型がどうシリアライズされるか、説明できるだろうか? non-contract typeの扱いは、知らないとハマる

*6:SOAPエンベロープはTextMessageEncodingBindingElementでもMessageVersion.Noneの時は出力されないし、それはBinaryMessageEncodingBindingElementなどでも同じことだから、区別の基準にはならない。