views:

734

answers:

1

I have a simple echo service where I've defined one operation method and a pair of types for request/response:

[ServiceContract(Name = "EchoService", 
                 Namespace = "http://example.com/services", 
                 SessionMode = SessionMode.NotAllowed)]
public interface IEchoService
{
    [OperationContract(IsOneWay = false,
                       Action = "http://example.com/services/EchoService/Echo", 
                       ReplyAction = "http://example.com/services/EchoService/EchoResponse")]
    EchoResponse Echo(EchoRequest value);
}

The data types:

[Serializable]
[DataContract(Namespace = "http://example.com/services/EchoService", 
              Name = "EchoRequest")]
public class EchoRequest
{
    public EchoRequest() { }

    public EchoRequest(String value)
    {
        Value = value;
    }

    [DataMember]
    public String Value { get; set; }
}

[Serializable]
[DataContract(Namespace = "http://example.com/services/EchoService", 
              Name = "EchoResponse")]
public class EchoResponse
{
    public EchoResponse() { }

    public EchoResponse(String value)
    {
        Value = value;
    }

    [DataMember]
    public String Value { get; set; }
}

Invoking Message.CreateMessage() on an instance of EchoRequest yields:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;
    <s:Header />
    <s:Body>
      <EchoRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/services/EchoService"&gt;
        <Value>hello, world!</Value>
      </EchoRequest>
    </s:Body>
  </s:Envelope>

...which is exactly what I want. However, it appears that the service is expecting the message body to be further wrapped in another XML element, like this:

  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;
    <s:Header />
    <s:Body>
      <Echo xmlns="http://example.com/services"&gt;
        <EchoRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.com/services/EchoService"&gt;
          <Value>hello, world!</Value>
        </EchoRequest>
      </Echo>
    </s:Body>
  </s:Envelope>

UPDATE: Thanks to Mark's reply, I've explored MessageContract instead of DataContract on the request/response types. This seems closer to what I want, but now it's going too far, and not expecting the outer type element, "EchoRequest".

This is confusing since somehow Message.CreateMessage appears to unfailingly produce the correct XML, so it's apparently using some default serialization which I'd like to configure the service to accept. Am I just misunderstanding how Message.CreateMessage works?

+1  A: 

IIRC, WCF by default uses the 'Wrapped' message style. If you want to be able to control how messages are serialized, you can define explicit messages by decorating with the MessageContractAttribute. With explicit message contracts, you can set the IsWrapped property to false.

In your case I think that EchoRequest and EchoResponse shouldn't be DataContracts at all, but rather MessageContracts. They look a lot like MessageContracts to me.

Mark Seemann
Thanks Mark, your suggestion lead me down a path which helped map my understanding of SOAP to WCF more closely. However, things are still not working quite right, and I edited the question, if you're game to follow up.
codekaizen