WCF REST Starter Kit Preview の Sample である FormPost では POST されたデータをオペレーションの引数でNameValueCollection として受け取るサンプルが掲載されています。これを可能にしているのは、Preview 版に含まれる FormsPostDispatchMessageFormatter を メッセージフォーマッタとして使用しているためです。今回はこのサンプルを見て、FormsPostDispatchMessageFormatterの機能を調べて見ます。

  • 動作環境:IIS6.0 on Windows Server 2003
  • 実装確認: Visaul Studio 2008 Professional
  • .NET 3.5 SP1, WCF REST Starter Kit Preview版

1. FormsPostDispatchMessageFormatter

WCF REST Starter Kit Preview 版に FormPost という Sample があります。このサンプルでは、Service クラスの SetData メソッドで、 NameValueCollection を引数にとるオペレーションが定義されています。NameValueCollection が定義されていると、フォームのポストデータが設定されて、オペレーションが呼び出されるようになります。

これを実現しているのがPreview版に含まれる FormsPostDispatchMessageFormatter です。メッセージフォーマッターは、同じく Preview 版に含まれる WebHttpBehavior2 という Behavior クラスでメッセージフォーマッタとして設定されるようになっています。 WebHttpBehavior2 は  WebServiceHost2  という ServiceHost  クラスのOnOpening()メソッド内で、カスタムバインディング構築時に、同時にすべてのエンドポイントのビヘイヴィアとして登録されます。WebHttpBehavior2とWebServiceHost2 は最終的には、 WebHttpBehavior, WebServiceHost に組み込まれるのかもしれません。

サンプルのServiceクラスの抜粋であるコードビハインドファイルの実装は次のようになっています。サービスのインスタンスコンテキストモードはシングルトンとなっています。ポストされるパラメタ/Service.svc/SetData/{a}?x={b}が呼び出された場合は、対応するシグネチャに値が設定され、NaveValueCollectionにポストされたデータが格納されます。/Service.svc/GetData がIEから呼び出されるとポスト時の設定されたデータが取得できます。

[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContract]
public partial class Service
{
    int value;

    [WebGet(UriTemplate = "GetData")]
    [WebHelp(Comment="Returns the value of the counter")]
    [OperationContract]
    Counter GetData()
    {
        return new Counter() { Value = this.value };
    }

    [WebInvoke(UriTemplate = "SetData/{a}?x={b}")]
    [WebHelp(Comment="Sets the value of the counter based on the value of the counter key in the incoming forms post data. Parameters a and b are unused.")]
    [OperationContract]
    void SetData(string a, NameValueCollection formsData, int b)
    {
        this.value = Int32.Parse(formsData["counter"]);
    }
}

Service.svc の実装方法などはサンプルを見ていただければ分かると思いますが、カスタムのファクトリWebServiceHost2Factoryをディレクティブで指定されていることが確認できます。このファクトリは内部でWebServiceHost2をサービスホストのインスタンスとして作成するファクトリです。

2. おまけ

こりずに FormPost のreadme.txt を翻訳してみます。

本サンプルでは、WCF REST サービスでどのようにフォームのポストデータを統合するかを例示しています。フォームのデータは引数にNameValueCollection 型をとるオペレーションメソッドを定義することによって読み取ることができるようになります。本サンプルでは加えて、 URI パラメタをポストボディとともに使用する方法も例示しています。

本サンプルを動作させる方法
========================
forms.htmをIEで表示します。 ページはテキストボックスに数字を入力するようになっています。データをポストしたあと、<host>/Service.svc/GetData にアクセスし、svc によってホストされるシングルトンカウンターリソースを取得します。取得されるカウンター値は、テキストボックスで入力した値になっているます。