Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 893
Jeroen-bart Engelen Avatar asked Mar 16 '09 10:03

Jeroen-bart Engelen


People also ask

What is WCF serialization and how does it work?

Windows Communication Foundation (WCF) can use two different serialization technologies to turn the data in your application into XML that is transmitted between clients and services, a process called serialization. By default WCF uses the DataContractSerializer class to serialize data types. This serializer supports the following types:

How do I deserialize XML in WCF?

When deserializing XML, the serializer uses the XmlReader and XmlWriter classes. It also supports the XmlDictionaryReader and XmlDictionaryWriter classes to enable it to produce optimized XML in some cases, such as when using the WCF binary XML format. WCF also includes a companion serializer, the NetDataContractSerializer.

What is datacontractserializer in WCF?

Windows Communication Foundation (WCF) includes a new serialization engine, the DataContractSerializer. The DataContractSerializer translates between .NET Framework objects and XML, in both directions.

How do I convert a WCF file to XML?

Using the XmlSerializer Class. Windows Communication Foundation (WCF) can use two different serialization technologies to turn the data in your application into XML that is transmitted between clients and services, a process called serialization.


2 Answers

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.)

like image 89
Rich Bayless Avatar answered Sep 20 '22 08:09

Rich Bayless


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.

like image 36
Richard Avatar answered Sep 22 '22 08:09

Richard