WCF REST Starter Kit Preview の Sample である PushStyleStreaming ではURLパラメタによって、コンテンツタイプがimage/jpegやtext/plain のストリームを返す方法を掲載しています。これは、Preview版に含まれる AdapterStream を使用することによって、本来Streamを扱えない.NET のクラスをWCF のストリーミングプログラミングモデルに適合させることによって、実現されています。今回はこの機能を調べて見ます。

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

1. AdapterStream

AdapterStream を使用することで、本来 Stream を返さない .NET のクラスを WCF の ストリームモデルに適合するように扱うことができるようにできます。AdapterStream を使用したサンプルは WCF REST Starter Kit Preview 版の PushStyleStreaming に含まれています。

ImageGenerationService.svc.cs のServiceクラスのソースプログラムのBitmapを返すオペレーションは次のように定義されています。

[WebHelp(Comment = "Returns a dynamically generated image based on input text")]
[WebGet(UriTemplate = "image?text={text}")]
[OperationContract]
Stream GetImage(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        throw new WebProtocolException(HttpStatusCode.BadRequest, "text must be specified", null);
    }
    Bitmap theBitmap = GenerateImage(text);
    WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
    return new AdapterStream((stream) => theBitmap.Save(stream, ImageFormat.Jpeg));
}

たったのこれだけで、画像をレスポンスとして出力できるようになりました。すばらしいです。重要なのは、 ContentType を image/jpeg にしていることとAdapterStreamのコンストラクタで設定されている、Action<Stream>のラムダ式です。ラムダ式で、 stream に画像を保存するようにすることで、 Stream の出力を実現しています。補足ですが、GenerateImageは引数の文字列を画像として含むようにプログラム上でBitmapを作成するメソッドでソースファイル上に定義されています。

サンプルにはもうひとつ、コンテンツタイプ text/plain を返すオペレーションメソッドが定義されています。

[WebHelp(Comment = "Generates response text dynamically based on input")]
[WebGet(UriTemplate = "text?text={text}")]
[OperationContract]
Stream GetText(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        throw new WebProtocolException(HttpStatusCode.BadRequest, "text must be specified", null);
    }
    WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
    return new AdapterStream((writer) =>
        {
            writer.WriteLine("You said: ");
            writer.WriteLine(text);
            writer.WriteLine("Didn't you?");
            writer.Flush();
        }, Encoding.UTF8);
}

AdapterStreamの引数に今度は、文字列を出力するラムダ式が設定されていることが確認できます。動作させると、コンテンツタイプがtext/plainのテキストがブラウザに表示されます。

2. おまけ

こりずに、Sample である、PushStyleStreaming の readme.txt の内容を翻訳してみます。

本サンプルでは、ビットマップやデータベースのAPIなど、ストリームを返さない.NET の API を WCFのストリーミングプログラミングモデルで使用する方法を説明しています。

本サンプルを動かすには
=================
本プロジェクトを実行します。ブラウザのアドレスに<host,port>/ImageGenerationService.svc/image?text=hello と入力します。ビットマップファイルが返されます。

サンプルのImageGenerationService.svc.csのソースを確認すると分かりますが。 /ImageGenerationService.svc/text?text=hello とアドレスに入力すると、コンテンツタイプがtext/plainのテキストがブラウザに表示されます。