ものがたり(旧)

atsushieno.hatenablog.com に続く

moonlight開発小話: cryptic hash in generic serialization

WCFのシリアライザ(DataContractSerializer)でgeneric typeを何も考えずに使うと、まるで意味の無いXMLが生成されることになるので気をつけたい。どう意味が無いかというと、XMLの要素名の最後に、謎のハッシュ文字列が追加されて意味が通らなくなるのである。

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.aspx
のcommunity contentsのところに、"How to use the Name property to generate nicer names for generic data contracts."というエントリがあって、そこで簡単に説明されているが、Foo<string>のような型を、何も考えずにDataContarctSerializerで生成すると、その名前はFooOfstringR4T64tyz みたいな名前になる(このハッシュはランダムに入力したので、実物は異なる文字列になる)。

data contractの情報のみから、このハッシュを計算するのは、計算式が公開されていない限り不可能だ。相互運用性という観点では、こういうgeneric typeのシリアライゼーションは全くcontract basedではない。

上記community contentsのエントリでも説明されているが、WCFでサービスを公開するユーザが、DataContractAttributeあるいはCollectionDataContarctAttributeを設定して、まともな名前が出力されるようにするのが、適切な解決方法だ。.NET同士でしか処理できない方法であれば、最初からバイナリデータでやり取りすればいい。XMLにする意味はほぼ無い。

困ったことに、.NET 3.5あるいはSP1から、WCFはDataContractAttributeの設定されていない型もDataContractSerializerで黙ってシリアライズするようになってしまった(まあ、winfx当初から id:atsushieno:20051008 で書いたように問題になっていたことではあるけど)。だから、ユーザが自分で問題のある実装を公開していないかどうか確認するのは容易ではない。

Hard Rock Cafeのサイトは、具体的にこれが問題になっている事例である。このサイトで使われているWCFのサービス情報はsvcで公開されている。ここで公開されているWSDLから参照されているXSDのひとつには、こんな記述がある:

<xs:element minOccurs="0" name="FilterData" nillable="true"
 type="q1:ArrayOfKeyValueOfFilterTypeArrayOfFilterHVmBUyjk"/>
<xs:element minOccurs="0" name="SortData" nillable="true" 
 type="q2:ArrayOfKeyValueOfSortTypeArrayOfintA6RxIDNe"/>

いずれも ArrayOfKeyValueOfFooBarHash という名前の構造になっている(Dictionary<K,V>をシリアライズするとこの形式の名前になる)。要するに、こんな暗号めいた要素が、XSDで定義されてWSDLで公開されてしまうことになる。

まあとりあえず、こういう困ったかたちのWCFサービスを公開して、それに依存しているSilverlightアプリケーションは、少なからず存在しているはずなので、moonlight的には実装でカバーしなければならなくなるだろう。というわけで、どうハッシュを計算しているのかはMSの担当の人へ問い合わせてもらっている。