views:

895

answers:

2

I'm trying to create a WSTransfer implementation (I realise Roman Kiss has written one already for WCF - but it doesn't actually meet the specifications)

I've ended up abandoning data contracts on the service contacts because WSTransfer is loosely coupled; so each the create message looks like Message Create(Message request).

This works fine, and everything is lovely until it's time to fire back a response.

The problem I have is in the way a WSTransfer response is constructed. Taking create as the example the response looks like

<wxf:ResourceCreated>
  <wsa:Address>....</wsa:Address>
  <wsa:ReferenceProperties>
    <xxx:MyID>....</xxx:MyId>
  </wsa:ReferenceProperties>
</wxf:ResourceCreated>

As you can see there are 3 different XML namespaces within the response message.

Now, it's easy enough when one is involved; you can (even if you're not exposing it), create a data contract and set the values and fire it back

Message response = Message.CreateMessage(request.Version, 
            "http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse",
            resourceCreatedMessage);

However the problem arises in setting different namespaces for the child elements within the response; it appears WCF's datacontracts don't do this. Even using

[MessageBodyMember(Namespace="....")]

on the individual elements within the response class don't appear to make any changes, everything becomes part of the namespace specified for the contract class.

So how do I apply different namespaces to individual elements in a WCF Message; either via a contract, or via some other jiggery pokery?

A: 

In a case like this when you need precise control over the XML output, you should use the the XmlSerializer instead of DataContract or MessageContract serialization. Here is more info on how to do that:

http://msdn.microsoft.com/en-us/library/ms733901.aspx

jezell
Been there, tried that; that fails even more horribly :)
blowdart
What wasn't working for you?
jezell
A: 

So following up jezell's answer; the problem with using XmlSerialization when creating a message by hand is that the child elements of the root get their element names mangled. This happens because despite the operation contract being marked as [XmlSerializerFormat] when you create a message by hand the DataContractSerializer is used.

You cannot pass the XmlSerializer into Message.CreateMessage() because it demands an XmlObjectSerializer, which XmlSerializer is not.

So the answer appears to be write a wrapper class for XmlSerializer, which has XmlObjectSerializer as its base class (here's an example) and pass that in; along with your message holding class.

Unfortunately it's not clever enough to setup prefixes in the XML; so you end up with messages like

<ResourceCreated xmlns="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <Address xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing/"&gt;http://localhost:8731/Design_Time_Addresses/AddTests/WSTransfer/&lt;/Address&gt;
  <ReferenceType xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing/"&gt;&lt;/ReferenceType&gt;

But it's all equivalent.

blowdart