Reputation: 1167
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
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
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