DCSIMG
Constructing an Empty WCF Reply Message - All Your Base Are Belong To Us

All Your Base Are Belong To Us

Mostly .NET internals and other kinds of gory details

Constructing an Empty WCF Reply Message

We're continuing the series of posts arising from the implementation intricacies of a WCF router.  Today's post features a seemingly simple task: Constructing an empty WCF reply message, which is the equivalent of the message sent in response to an operation which returns void (but is not one-way).

The motivation for this could be the following: A router needs to dispatch a message to multiple subscribers.  However, the router itself is unaware of the data contract - it is willing to work on an untyped Message-based contract.  The operation doesn't have a return type - it's void.  On the other hand, the operation is not one-way for some reason - for example, it might require transactional semantics to assure that the message is delivered and made durable as part of the client transaction.  This would require the router to construct the semantic equivalent of the message that would be sent in response to the operation if the service was working with the original contract, and not the untyped Message-based contract the router is familiar with.

Let's observe the request and reply messages for a simple operation called Hello which takes a string parameter.  The request message looks like this:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"

            xmlns:a="http://www.w3.org/2005/08/addressing">

  <s:Header>

    <a:Action s:mustUnderstand="1">

        http://tempuri.org/IHello/Hello

    </a:Action>

    <a:MessageID>urn:uuid:2ec62f21-b334-4e50-85e0-586decdef121</a:MessageID>

    <a:ReplyTo>

      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>

    </a:ReplyTo>

    <a:To s:mustUnderstand="1">http://localhost:9090/Hello</a:To>

  </s:Header>

  <s:Body>

    <Hello xmlns="http://tempuri.org/">

      <str>Hello World!</str>

    </Hello>

  </s:Body>

</s:Envelope>

And the response message looks like this:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"

            xmlns:a="http://www.w3.org/2005/08/addressing">

    <s:Header>

        <a:Action s:mustUnderstand="1">

            http://tempuri.org/IHello/HelloResponse

        </a:Action>

        <a:RelatesTo>

            urn:uuid:2ec62f21-b334-4e50-85e0-586decdef121

        </a:RelatesTo>

    </s:Header>

    <s:Body>

        <HelloResponse xmlns="http://tempuri.org/" />

    </s:Body>

</s:Envelope>

This seems simple enough to fake.  The RelatesTo header is not critical (it provides the correlation between the request and response messages, but we can live without it).  The Action header must be present, and the response body has to be present because that's what the operation formatter on the client side expects.

I wasn't able to find an elegant way to generate the response - all relevant classes which implement IDispatchOperationFormatter are internal, and considered an implementation detail.  Therefore, I had to resort to the following (highly fragile) code to construct the response message:

XmlDictionaryReader requestReader =

    message.GetReaderAtBodyContents();

string bodyElemName = requestReader.Name;

string bodyNS = requestReader.NamespaceURI;

requestReader.Close();

 

XmlDictionaryReader bodyReader =

    XmlDictionaryReader.CreateDictionaryReader(

        XmlReader.Create(

            new StringReader(

                "<" + bodyElemName + "Response " +

                "xmlns='" + bodyNS + "' />"

                )));

 

Message reply = Message.CreateMessage(

    message.Version,

    message.Headers.Action + "Response",

    bodyReader);

It works, but if there's a better way that you can think of, I'd be delighted to hear about it.

Comments

I Love C# said:

בעקבות הפוסט (Constructing an Empty WCF Reply Message) הבנתי שהרבה אנשים רוצים דרך ליצור הודעות בקשה

# June 18, 2008 12:18 AM

Yaron said:

Sasha

I think there is a problem with the requirement itself: In principal the response message can have any root element name and any wsa:Action. You can't count on the convention of [RequestElemName]Response.

# June 20, 2008 6:38 PM

Yaron said:

Sasha

I am also implementing such a router and I have encountered a problem: I want the router to communicate with the actual server using MTOM. However since the router uses untyped messages it does not know which message parts are base64 and thus does not optimize anything even if I configure it to use MTOM. Do you have any idea if this is solvable?

# June 20, 2008 6:42 PM

Sasha Goldshtein said:

As I said, this code is fragile but it solves the common case.  For the general case, I agree that you have no way of knowing what response the service you're impersonating would have generated.

# June 22, 2008 8:38 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: