このブログの WCF の記事、全部日本語ページへのリンクに張り替えないと。。。
WsdlExporter クラスには、開発者が WSDL のエクスポートをカスタマイズできるような仕組みが備わっています。
WSDL のエクスポートをカスタマイズするには、IWsdlExportExtension インターフェイス(System.ServiceModel.Description) を実装したクラスを用意します。
更にこのクラスは、コントラクトビヘイビア、エンドポイントビヘイビア、オペレーションビヘイビア、バインディング要素のいずれかとして実装します。 ( これら特有のインターフェイスを実装する際は、特になんらかの処理を行う必要はありません。例えば、コントラクトビヘイビアならIContractBehavior インターフェイスを実装しますが、このインターフェイスの各メソッドの中身は空で大丈夫です。なお、サービスビヘイビアは含まれていないことに注意します。 )
IWsdlExportExtension インターフェイスには次の二つのメソッドが用意されています。
各メソッドは、第一引数で呼び出し元の WsdlExporter を受け取り、第二引数でカスタマイズを行うためのオブジェクトを受け取ります。
・ExportContract メソッド
コントラクトに対して生成される WSDL をカスタマイズします。
第二引数で受け取った WsdlContractConversionContext クラス (System.ServiceModel.Description) のオブジェクトに対してカスタマイズを行います。
・ExportEndpoint メソッド
エンドポイントに対して生成される WSDL をカスタマイズします。
第二引数で受け取った WsdlEndpointConversionContext クラス (System.ServiceModel.Description) のオブジェクトに対してカスタマイズを行います。
[ 関連記事 ]
C#と諸々 - 独自のビヘイビアを定義する
C#と諸々 - 独自のビヘイビアを定義する2
[ MSDN 関連記事 ]
メタデータ システムの拡張
WCF 拡張に対するカスタム メタデータのエクスポート
方法 : カスタム WSDL をエクスポートする
ServiceDescription と WSDL 参照
System.ServiceModel.Description 名前空間
System.Web.Services.Description 名前空間
独自のビヘイビアを定義する
ビヘイビアの種類の紹介に、コントラクト ビヘイビアとオペレーション ビヘイビアを追加しました。
各ビヘイビアで利用できる適用方法に関する説明を追加しました。
構成を一部変更しました。
独自のビヘイビアを定義する2
カスタム属性として定義できるビヘイビアについての説明を追加しました。
オペレーション コントラクトを定義する方法を削除しました。
以上。
それぞれ違うユーザー情報を返してきた時は驚いた。
・WindowsIdentity クラス (System.Security.Principal) の GetCurrent メソッド
現在実行中の Win32 スレッドのセキュリティ コンテキストの ID 情報を返します。
・Thread クラス (System.Threading) の CurrentPrincipal プロパティ
Win32 スレッドの上位で、現在実行されている .NET スレッドのプリンシパルを返します。
なるほど、型の違いと、Thread.CurrentPrincipal だけが設定可能なのはこういう理由か。
[ 参考 ]
ASP.NET ID マトリックス
.NET Framework のユーザー操作の基礎
その時は System.Environment クラスの GetFolderPath メソッドを使おうとしていたんだけど、このメソッドのパラメータの型は System.Environment.SpecialFolder 列挙体。この列挙体は System.Environment の入れ子型として定義されている。
最初、この列挙体の値を
[System.Environment.SpecialFolder]::MyMusic
といった感じで取得できると思っていたら、ダメだった。System.Environment.SpecialFolder なんていう型は存在しないと怒られる。
CLR が入れ子型をどのように扱っているか見てみると、その入れ子型を含んでいる型名と入れ子型名を "+" で繋いでいるようだ。
つまり System.Environment の入れ子型 SpecialFolder なら System.Environment+SpecialFolder となる。
PowerShell で
[System.Environment+SpecialFolder]::MyMusic
と入力して Enter を押すと、SpecialFolder 列挙値を取得できた。
まぁ、PowerShell だと列挙値の指定の際に、文字列でその列挙値の名前指定することもできるから、今回の場合は
[System.Environment]::GetFolderPath("MyMusic");
って入力すればそれで事足りた訳だけど、すっかり忘れていた^^;
もう一ヶ月以上経つのですが、実は子供が産まれました。
元気な男の子で、毎日大声でオギャオギャ泣いております。まだ笑ったりはしないのですが、もう見てるだけで和みますw
で、その関係で今までほど PC と睨めっこしていられなくなりました。代わりに子供と睨めっこです ^^;
このブログの更新頻度も落ちています。前に言ってたホームページ作成の件も完全に中断しています。こちらの記事でコメントしてくださった ほにゃさん ( そして、いるかどうかはわかりませんが、他にも期待してくださっていた方 ) には本当に申し訳ないです。
思えば、リフレクション入門用の記事も2回でストップしてます。リフレクションで検索してここに飛んでくる方もけっこういらっしゃいますが、ホントすみません。。。
これからは、ブログの更新もあまりできないかもしれませんが、やめるつもりはありません。今後とも、よろしくお願いいたします m(_ _)m
あの後、実は指定できないこともないということに気づきました。ごめんなさい。
まず、なぜうまく指定できないと書いたかですが、先日の記事であげたケースと物品の例で説明します。
ケース クラスには格納する物品を指定するためのジェネリックパラメータを用意します。
物品 クラスには親となるケースを指定するためのジェネリックパラメータを用意します。
つまり、ケース<TArticle> クラスと 物品<TCase> クラス となるわけです。
この時、ケース クラスのジェネリックパラメータ TArticle の型制約には、物品<TCase> を指定するわけですが、物品<TCase> の型パラメータ TCase を指定しなければなりません。ここで不都合が生じるわけです。TCase に対して ケース<TArticle> と指定することはできますが、これではダメなんです。
なぜ不都合かというと、ジェネリック クラスは、型パラメータが完全一致していない場合、変換不可だからです。例えば、List<object> と List<int> では、object と int の間には継承関係がありますが、そんなの関係なく変換不可です。List<int> 型の変数を List<object> 型にキャストすることはできないのです。
すると、TCase が指定できないことがわかります。例えば、ケース クラスを継承した CDケース クラスでは、TCase は、CDケース にならなければなりません。ケース<CD> ではダメなのです。 ( 物品<ケース<CD> は 物品<ケース> への変換が不可ということです。 )
と、ちょっとややこしい話になってしまいましたが、要はこのままでは型制約の指定は無理だということです。で、先日の記事には無理だよ~と書いたわけです。
では、どうすればいいか、というのが今回の記事の本題です。
答えは、「自身のクラス階層を含め、ミラー階層において関連するクラス ( 階層 ) 全てを型パラメータに持たせる」 となります。
つまり、ケースには TCase と TArticle の2つの型パラメータを持たせ、物品にも TCase と TArticle の2つの型パラメータを持たせるわけです。
こうすることによって、先ほどの問題が解決できます。先ほど指定できなかった TCase には、ケースに新しく追加した型パラメータ TCase を指定すればいいわけですから。
コードにすると以下のようになります。
public abstract class ケース<TCase, TArticle>
where TCase : ケース<TCase, TArticle>
where TArticle : 物品<TCase, TArticle>
{
}
public abstract class 物品<TCase, TArticle>
where TCase : ケース<TCase, TArticle>
where TArticle : 物品<TCase, TArticle>
{
}
これらを継承した CDケース クラスと CD クラスは以下のようになります。
public sealed class CDケース : ケース<CDケース, CD>
{
}
public sealed class CD : 物品<CDケース, CD>
{
}
TCase と TArticle に関連しない型を指定した場合 ( 例えば ケース<CDケース, ペン> ) 、コンパイルエラーとなりますので、変なバグが入り込んだりすることはないかと思います。
これで問題は解決しましたが、一つ気を付けなければならないことがあります。ケース クラスに TCase という型パラメータ、そして 物品 クラスに TArticle という型パラメータがあることは、他人から見ておかしなことをやっているように見えてしまう ( つまり理解し難い ) ということです。こればかりは仕方ありませんので、理由や使い方をしっかりとドキュメントに書き記すようにしましょう。( いや、理由はしっかり書くとややこしくなるからざっくりとの方がいいかもw )
[ 余談 ]
ちなみに、これ以外にも方法はあります。非ジェネリックな基本クラスを用意するという方法です。つまり、「ケース クラス」 とこれを継承した 「ケース<TArticle> クラス」、「物品 クラス」 とこれを継承した 「物品<TCase> クラス」 を用意するわけです。こうすれば、型制約には非ジェネリックな基本クラスを指定することができます。