WCF 入門 (3) ~ 送受信されたメッセージを見る

これまで作成したプログラムでメッセージの送受信が行われたことは見てきました。 ここでは、そのときにどのようなメッセージを受け渡ししていたのか確認してみましょう。

前回作成した HelloWCF.cs のみを次のように変更します。

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

public class HelloWCF : IHelloWCF {

     HelloWCF() {
          Console.WriteLine ( "HelloWCF: Object created" );
     }

     public void Say( string input ) {

          Console.WriteLine ( "HelloWCF: Message Received [{0}]", input );
          Message msg = OperationContext.Current.RequestContext.RequestMessage;           Console.WriteLine ( "Request Message:" );           Console.WriteLine ( " State : {0}", msg.State.ToString() );           Console.WriteLine ( msg.ToString() );
     } }

変更したファイルを含む HelloWCFReceiverApp.exe のみ再コンパイルします。 私は名前を HelloWCFReceiverApp2.exe に変更しました。

再コンパイルして、出来上がった HelloWCFReceiver2.exe を実行し、 HelloWCFSender.exe を実行すると次のようになりました。

>csc /out:HelloWCFReceiver2.exe HelloWCF.cs IHello
WCF.cs HelloWCFReceiverApp.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.


>HelloWCFReceiver2.exe
HelloWCFReceiverApp: Wainting for messages...
HelloWCF: Object created
HelloWCF: Message Received [Hello, WCF!]
Request Message:
 State  : Read
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" 
        xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">
        http://localhost:4000/IHelloWCF
    </To>
    <Action s:mustUnderstand="1" 
        xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">
        http://tempuri.org/IHelloWCF/Say
    </Action>
  </s:Header>
  <s:Body>
    <Say xmlns="http://tempuri.org/">
      <input>Hello, WCF!</input>
    </Say>
  </s:Body>
</s:Envelope>

表示された XML メッセージが "クライアントから送られてきたメッセージ" です。この中に、 確かに "Hello, WCF!" という文字列が入っていることがわかります。(しかし後述の通り、これは厳密にクライアントが送信したメッセージではありません)

尚、この XML は SOAP メッセージです。SOAP 1.1 メッセージ です。インターオペラビリティを重視して、あえて古い仕様をデフォルトにした、 ということでしょうか。(参考: SOAP 仕様書)

しかし、この SOAP メッセージは実際に送信されたものではない...

せっかく独自のプロトコルではなく SOAP を使っているのですから、他の SOAP クライアントからもこのレシーバープログラムにアクセスできることを確認しておきましょう。

WFetch を用いて SOAP メッセージを送信するために、以下のように設定します。

Verb: POST
Host: localhost
Port: 4000
Ver: 1.1
Path: /IHelloWCF
Advanced Request: Add Headers & Body

その下の空欄に次のように入力します。

Host: localhost:4000
Content-Type: text/xml; charset="utf-8"
SOAPAction: "http://tempuri.org/IHelloWCF/Say"

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <Say xmlns="http://tempuri.org/">
      <input>Hello, I'm WFetch!!</input>
    </Say>
  </s:Body>
</s:Envelope>

上記のメッセージを送信すると、確かに以下のように受信プログラムでメッセージを受け取れたことがわかります。

> HelloWCFReceiver2.exe
HelloWCFReceiverApp: Wainting for messages...
HelloWCF: Object created
HelloWCF: Message Received [Hello, I'm WFetch!!]
Request Message:
 State  : Read
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addr
essing/none">http://localhost:4000/IHelloWCF</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/
addressing/none">http://tempuri.org/IHelloWCF/Say</Action>
  </s:Header>
  <s:Body>
    <Say xmlns="http://tempuri.org/">
      <input>Hello, I'm WFetch!!</input>
    </Say>
  </s:Body>
</s:Envelope>

この実験をしてわかったのですが、OperationContext から取得できる RequestMessage と、 実際に送信された SOAP メッセージ (XML) は違います。 上記、WFetch で送信したメッセージと受信プログラムでの出力が異なることに注意してください。 受け取り側の RequestMessage オブジェクトには Header が付いています。

上記のコンソールへの出力通りの SOAP ヘッダ付きのメッセージを WFetch で送信すると、400 Bad Request が返されます。

どうしてこんなややこしいことになっているのか、よくわかりませんが、現状そのような実装のようです。 WCF 上のプログラム同士以外との接続時に気をつけると良いと思います。

OperationContext

OperationContext を用いて実行環境のコンテキストにアクセスすることができます。Current プロパティは static プロパティであり、 現在のコンテキストを取得できます。

プロパティ
Current現在の実行コンテキストを表す OperationContext オブジェクトを返します。
ServiceSecurityContextメソッドが実行されるセキュリティ環境を返します。
EndpointDispatcher操作の System.ServiceModel.Dispatcher..::.EndpointDispatcher を取得します。
Extensions現在の OperationContext の拡張のコレクションを返します。
Hostサービスを管理する ServiceHostBase オブジェクトを返します。
HasSupportingTokensメソッドがトークンをサポートしているかどうかを示す値を返し、サポートしている場合は、SupportingTokens プロパティがトークンを取得します。
IncomingMessageHeaders、IncomingMessageProperties、および IncomingMessageVersion の各プロパティ 対応する項目を受信メッセージから取得します。
OutgoingMessageHeadersと OutgoingMessageProperties送信メッセージの対応する項目を取得します。
RequestContextメソッドの RequestContext 実装を返します。
InstanceContext操作に関連付けられた InstanceContext を返します。
SessionId現在のチャネルとオブジェクトのセッション ID を返します。
メソッド
GetCallbackChannel<(Of <(T>)>)は、双方向通信の場合に、呼び出し元へのコールバック チャネルを返します。
SetTransactionComplete現在のトランザクションをコミットします。
イベント
OperationCompleted操作が完了したときに発生します。

詳細は MSDN の OperationContext に関する説明 をみてください。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説