views:

3576

answers:

1

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?

+1  A: 

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.

Richard
Like I already stated in the question, I've tried adding an XmlRoot attribute and it didn't work. It only adds the namespace to the fields within MyClass, but not to MyClass itself.The DataContract also doesn't work, and I prefer the XmlSerializer because of renaming and order isn't important then.
Jeroen-bart Engelen
I used svcutil, but without specifying a serializer and it generated a combination of MessageContract and ServiceContract with XmlSerializer. So it has one or two wrappers and I could still use the XML attributes to make it all work.
Jeroen-bart Engelen
@Jeroen: Please add the solution svcutil provided here for others benefit. Thanks.
Richard