Error 415 and WCF Compatibility between .Net 2.0 and 3.5
If you try to call a 3.5 WCF Service with the framework 2.0 and WCF 3.0, you will have an error 415 :
Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected type 'application/soap+xml; charset=utf-8'
'text/xml' is the content type for SOAP 1.1 while 'application/soap+xml' is the content type for SOAP 1.2 and your client WCF 3.0 use SOAP 1.1 while the service with WCF 3.5 use SOAP 1.2.
Here is the solution that worked for me. If you have access to the service config, you just have to change the binding to use SOAP 1.1 :
Add a new custom binding in the 'bindings' section
<customBinding>
<binding name="Soap11HttpBinding">
<textMessageEncoding messageVersion="Soap11" />
<httpTransport />
</binding>
</customBinding>
and don't forget to update your endpoint with the new binding :
<endpoint ...
binding="customBinding"
bindingConfiguration="Soap11HttpBinding">
...
</endpoint>
WCF WSDL SOAP binding: Rpc or Document, Encoded or Literal
Yeah, my new WebService must be Rpc/Encoded. What ????
Hopefully this page from Ibm explain the different style/use in SOAP message.
A WSDL document describes a Web service. A WSDL binding describes how the service is bound to a messaging protocol, particularly the SOAP messaging protocol. A WSDL SOAP binding can be either a Remote Procedure Call (RPC) style binding or a document style binding. A SOAP binding can also have an encoded use or a literal use.
Ok now I know that four style/use models:
RPC/Encoded, RPC/literal, Document/encoded or Document/literal
But how do I do that in WCF C# ?? It's very easy, just use the [XmlSerializerFormat] attribute.
Here is a very very simple test to check the different result in the soap message:
Interface of the Wcf service used :
using System.ServiceModel;
namespace WcfService1
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc, Use = OperationFormatUse.Encoded)]
string TestRpcEncoded(int value);
[OperationContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc, Use = OperationFormatUse.Literal)]
string TestRpcLiteral(int value);
//[OperationContract]
//[XmlSerializerFormat(Style = OperationFormatStyle.Document, Use = OperationFormatUse.Encoded)]
//string TestDocumentEncoded(int value);
[OperationContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Document, Use = OperationFormatUse.Literal)]
string TestDocumentLiteral(int value);
}
}
Result captured on the network with fiddler:
For clarity, I have removed:
- s:Envelope tag
- xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns="http://tempuri.org/"
RPC / Encoded call
<!-- Request -->
<s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<q1:TestRpcEncoded>
<value xsi:type="xsd:int">42</value>
</q1:TestRpcEncoded>
</s:Body>
<!-- Response -->
<s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<q1:TestRpcEncodedResponse>
<TestRpcEncodedResult xsi:type="xsd:string">You entered: 42</TestRpcEncodedResult>
</q1:TestRpcEncodedResponse>
</s:Body>
RPC / Literal call
<!-- Request -->
<s:Body>
<TestRpcLiteral>
<value xmlns="">42</value>
</TestRpcLiteral>
</s:Body>
<!-- Response -->
<s:Body>
<TestRpcLiteralResponse>
<TestRpcLiteralResult xmlns="">You entered: 42</TestRpcLiteralResult>
</TestRpcLiteralResponse>
</s:Body>
Document / Encoded call
If you add the TestDocumentEncoded you will get an InvalidOperationException.
This combination is not supported.
Document / Literal call
<!-- Request -->
<s:Body></code>
<TestDocumentLiteral><value>42</value></TestDocumentLiteral>
</s:Body>
<!-- Response -->
<s:Body>
<TestDocumentLiteralResponse>
<TestDocumentLiteralResult>You entered: 42</TestDocumentLiteralResult>
</TestDocumentLiteralResponse>
</s:Body>