I’ve acquired more information since the original post and have been able to recreate the problem in a very simple File > New Project > WCF Service Application solution. As a result I’m heavily editing the original content of this post to get rid of some of the superfluous information and simplify the examples:
We have a message contract defined as follows.
[MessageContract( WrapperName = "SingleTypeResponse", WrapperNamespace = "urn:WcfService1" )]
public class SingleTypeResponse<T>
{
[MessageBodyMember( Name = "ReturnValue" )]
public T ReturnValue { get; set; }
}
The service interface has the following:
[OperationContract]
SingleTypeResponse<string> GetStringData();
[OperationContract]
SingleTypeResponse<int> GetIntData();
When I run the project and navigate to the .svc file I get the following:
An exception was thrown in a call to a WSDL export extension: System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://tempuri.org/:IService1 —-> System.InvalidOperationException: The WcfService1.IService1.GetIntData operation references a message element [urn:WcfService1:SingleTypeResponse] that has already been exported from the WcfService1.IService1.GetStringData operation. You can change the name of one of the operations by changing the method name or using the Name property of OperationContractAttribute. Alternatively, you can control the element name in greater detail using the MessageContract programming model.
If I comment out GetIntData on the interface and test the service using the WCF Test Client, with the WrapperName property set, I get the following response XML:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<SingleTypeResponse xmlns="urn:WcfService1">
<ReturnValue xmlns="http://tempuri.org/">foo</ReturnValue>
</SingleTypeResponse>
</s:Body>
</s:Envelope>
I’m guessing that element is the source of the problem, it sees two versions of the same element, one with a string and one with an int.
I then uncommented the GetIntData and removed the WrapperName property from the MessageContract:
[MessageContract( WrapperNamespace = "urn:WcfService1" )]
public class SingleTypeResponse<T>
{
[MessageBodyMember( Name = "ReturnValue" )]
public T ReturnValue { get; set; }
}
I get the same error message with the exception that the message element it’s complaining about is the ReturnValue property of the contract rather than the message contract name.
Once again commenting out GetIntData and testing with WCF Test Client I get:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<SingleTypeResponseOf_String xmlns="urn:WcfService1">
<ReturnValue xmlns="http://tempuri.org/">foo</ReturnValue>
</SingleTypeResponseOf_String>
</s:Body>
</s:Envelope>
So I’m able to get it to create a unique name for the wrapper, but the fact that SingleTypeResponseOf_String and SingleTypeResponseOf_Int32 both have a ReturnValue property continues to cause it to blow its brains out.
I’ve never thought about it before but it makes sense that generic types need to be defined as concrete types for a WSDL. Coming from that perspective, it appears that yes – you are defining two ‘types’ of
SingleTypeResponsein your service. WSDL does not allow two element definitions of the same name & namespace to coexist (for obvious reasons – they need to be uniquely identifiable).There are a couple of potential conflicts here. I think you’ve identified the first one – an element named
SingleTypeResponsewithin theurn:WcfService1namespace. When you turn off the naming of the message contract (allowing it to be named by the serializer) you see the below:This should avoid the first conflict, because running your two operations means that you’ll be able to have two types of element (
SingleTypeResponseOf_StringandSingleTypeResponseOf_Int).I believe your second conflict comes from the
MessageBodyMemberattribute. Because both the operations define messages in the same namespace, and both return types contain an elementReturnValue, you will get a conflict where theurn:ReturnValueelement is defined twice, once as an int and once as a string.To demonstrate see the following, with the
GetIntDataoperation comment out, see theReturnValueelement defined:How can you allow the
MessageContractto rename theReturnValueproperty? I don’t think you can with DataContractSerializer.What’s the solution? Well, I don’t think there is a solution using
[MessageBodyMember]. If you use[DataMember]it will work fine. You mentioned before that you’re using net.tcp, so I assume your .NET to .NET. Do you need to exercise that level of control of the SOAP envelopes?Normally I use
DataContractas much as possible, and only venture intoMessageContractwhen necessary – interfacing with older SOAP style platforms.