.net – WCF: Data contract being converted to message contract

datacontractmessagecontractnetwcf

My WCF service exports a single operation, marked with the catch-all action and reply action so that it represents a common entry point to the service:

[ServiceContract]
public interface IService
{
    [OperationContract (Action="*", ReplyAction="*")]
    Message MyMethod (Message msg);
}

Client proxies are still generated as data contracts.

What I'm finding, however, is that despite the client sending a data contract, when msg is serialized, the body appears to be the equivalent message contract to the data contract, not the data contract itself.

Even this is fine, except that extracting the data contract inside involves doing a manual parsing of the incoming XML. The service itself does not have an actual MessageContract type to use, so accessing the body means extracting nodes, relabeling elements, and so on. It's a manual process for something that, presumably, WCF is already handling under the covers when the exposed operations are not Message-based.

How does WCF do this when it's data contract-to-data contract? Is there a way that I can use that same process?

Best Answer

That is the correct default behavior. Each time a request or a response data are send they are automatically wrapped in the wrapping element. It is also known as Wrapped parameter style. If you don't want to use it and instead you want to use Bare parameter style you have to define message contract and set its IsWrapped property to false. Like this simple example:

[ServiceContract]
public interface IService
{
    [OperationContract]
    GetMessageResponse GetMessage(GetMessageRequest request);
}

[MessageContract(IsWrapped = false)]
public class GetMessageResponse
{
    [MessageBodyMember]
    public string Result { get; set; }
}

[MessageContract(IsWrapped = false)]
public class GetMessageRequest
{
    [MessageBodyMember]
    public string Data { get; set; }
}

GetMessage operation will not use wrapping in request and response.

Limitation is that operation has to accept only single MessageContract as the parameter and always has to return MessageContract (even if it returns void). So the easiest way to achieve your requirement is to convert all your data contracts to message contracts by replacing attributes.

Another way is to create separate message contract for each request and response and use properties of your data contracts types as message body. If for any reason you don't like the idea of creating two additional message contracts for each operation and you still want to preserve old data contracts you can use little hack (I don't see any reason for using it but it works). Add MessageContract attribute to your data contracts and MessageBodyMember attribute to all your data members.

[DataContract, MessageContract(IsWrapped = false)]
public class MyData
{ 
    [DataMember, MessageBodyMember]
    public string Data { get; set; }
}
Related Topic