Jeroen-bart Engelen
Jeroen-bart Engelen

Reputation: 1167

How to customize WCF XML serialization

We have an existing SOAP web service interface that we want to implement using WCF for a new application. This seems to work fine except for one small detail. The XML namespace of the return type of a function must be different than the XML namespace of the web service itself. And for the life of me, I can't get it to work.

I've recreated the same problem with a small sample project. The WCF interface:

[XmlSerializerFormat]
[ServiceContract(Namespace = "urn:outer-namespace")]
public interface IService1
{
    [OperationContract]
    MyClass DoStuff(int value);
}

[Serializable]
public class MyClass
{
    [XmlElement(ElementName = "DataString")]
    public string MyString { get; set; }
}

The web service implementation:

    public class Service1 : IService1
{
    public MyClass DoStuff(int value)
    {
        return new MyClass { MyString = "Wooh!" };
    }
}

A response from this webservice is then serialized as: (Omitting SOAP stuff)

  <DoStuffResponse xmlns="urn:outer-namespace">
     <DoStuffResult>
        <DataString>Wooh!</DataString>
     </DoStuffResult>
  </DoStuffResponse>

But we want the <DoStuffResult> to be of xmlns="urn:inner-namespace".

I've tried adding a [return: XmlElement(...)] on the interface function or the web service function, but that doesn't take. Also an [XmlType] or [XmlRoot] on the MyClass class definition doesn't work.

Does anyone have an idea how to change the serialized XML namespace (or element name) of the object that is the return value of a WCF web service function?

Upvotes: 8

Views: 22248

Answers (2)

Rich Bayless
Rich Bayless

Reputation: 153

After days of searching and trying dozens of recommended solutions; I was finally able to get WCF to stop forcing a wrapper container name of appending Result to the name of the web service method. The trick was to add the following decorator attribute to the web service interface:

[return:MessageParameter(Name = "whatIWantItNamed")]

This attribute should be placed/located directly after the [OperationContract] attribute (and just before the actual method stub) in the interface.

(I also needed to add an XmlSerializerFormat attribute to all of the ServiceContract and OperationContract attributes.)

Upvotes: 5

Richard
Richard

Reputation: 108975

Define namespaces with the XML Serialisation (or, better) Data Contract definition attributes.

e.g. with XML Serialisation:

[Serializable, XmlRoot(namespace="http://example.com/eg1")]
public class MyClass {
  [XmlElement(ElementName = "DataString")]
  public string MyString { get; set; }
}

e.g. with Data Contract serialisation:

[DataContract(Namespace="http://example.com/eg2")]
public class MyClass {
  [DataMember]
  public string MyString { get; set; }
}

EDIT

Based on the first comment, the above won't work, because the desire is to set the namespace on the SOAP wrapper around the message, not on the message itself.

OperationContractAttribute offers no control of namespaces, and I can't see any other WCF attributes at a method level.

Two possibilities: (1) You may have enough control by dropping a level of abstraction and using a Message Contract. (2) Get the current WSDL for the service (using svcutil.exe), manually adjusting it to get the namespaces you want, and then using svcutil.exe again to generate the code, and look at the resulting code.

Upvotes: 3

Related Questions