views:

2589

answers:

1

We've inherited a WCF web service that has a custom MessageFormatter that constructs a custom Message subclass in the SerializeReply Method.

class OurMessageFormatter : MessageFormatter
{
  public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
  {
    OurResponse ourResponse = (OurResponse) result;

    // some validation here...

    OurMessage reply = new OurMessage(ourResponse, MessageVersion.Soap11);
    return reply;
  }

}

The problem we're facing is that the custom Message subclass wouldn't have any headers populated. We tried to see if WCF would populate the generic ones (MessageID, ResponseTo, Action and such) out of the box, but no luck. Then we realized that the custom Message subclass had implemented the Headers Property like so...

class OurMessage : Message
{
  public override MessageHeaders Headers
  {
    get { return new MessageHeaders(MessageVersion.Soap11WSAddressing10); }
  }
}

... lotta help that turned out to be! So we rewrote it as so...

class OurMessage : Message
{
  MessageHeaders headers;

  public OurMessage()
  {
    // ...

    headers = new MessageHeaders(MessageVersion.Soap11WSAddressing10);
  }

  public override MessageHeaders Headers
  {
    get { return headers; }
  }
}

... and still no luck.

So we went on to hand code the headers; first in the Formatter...

class OurMessageFormatter : MessageFormatter
{

  public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
  {
    //...

    OurMessage reply = new OurMessage(ourResponse, MessageVersion.Soap11);
    ourMessage.MessageID = ...;
    ourMessage.ResponseTo = ...;
    ourMessage.Action = ...;
    // more headers set ...

    return reply;
  }

}

... and then in the Message itself...

class OurMessage : Message
{
  public override MessageHeaders Headers
  {
    get
    {
      MessageHeaders headers = new MessageHeaders(MessageVersion.Soap11WSAddressing10);
      ourMessage.MessageID = ...;
      ourMessage.ResponseTo = ...;
      ourMessage.Action = ...;
      // more headers set ...

      return headers;
    }
  }
}

Every way we tried, we managed to get the WS-Addressing headers into the actual response, but could never get the WS-Security header in (actually we were just trying to put in a Security Header with TimestampID and Created/Expires elements). Every time we added the Security header in the Security header, the service just dropped the connection unexpectedly during serialization (after the SerializeReply call had completed).

So here's my question. Does anyone know how to get the WS-Security headers into a WCF service with custom Formatter and custom Message implementation?

Update [26 Nov 2008]: We have an outstanding MS incident for this and the latest update we got from them was that WCF's current MessageVersion's don't seem to support those headers and need a custom binding implementation. The investigation continues for better approaches.

+1  A: 

I noticed that the MessageHeaders class has a constructor that takes a collection of MessageHeaders as a parameter. Maybe you could pass the complete collection of headers you need to see if it works. I haven't worked with WS-Security headers before so I'm not sure this is feasible for them. I know that they will be in their own namespace (wsse:http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd) that will need to be defined for the message header.

I found this article that gives a good overview of Messaging Fundamentals. It has an example on creating headers.

Sixto Saez
Not sure what you're hinting at. We don't have any headers to start with, so I can't see the copy constructor working.
dexterous