I'm learning WCF, specifically I'm learning how to write them contract first, ala wscf.blue
I can create a WCF client/service the contract last way (Microsoft) I can create a WCF client/service the contract first way (WSCF)
But, if I create a contract first service, then try to add it the Microsoft way (Service Reference) instead of the WSCF.blue way (share contract and generate client) it doesn't work.
It throws an ActionNotSupportedException
with the message The message with Action 'urn:test-com:simple:testMethodIn' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
And I have no idea what that means.
Here is my test contract:
SimpleModel.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="urn:test-com:simple" xmlns:mstns="urn:test-com:simple" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:test-com:simple" elementFormDefault="qualified" attributeFormDefault="unqualified" id="SimpleModel">
<xs:complexType name="PayloadType">
<xs:sequence>
<xs:element name="AString" type="xs:string" nillable="1" minOccurs="0"/>
<xs:element name="AnInt" type="xs:int"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
SimpleMessages.xsd
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="urn:test-com:simple" xmlns:mstns="urn:test-com:simple" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:smod="http://tempuri.org/SimpleModel.xsd" targetNamespace="urn:test-com:simple" elementFormDefault="qualified" attributeFormDefault="unqualified" id="SimpleMessages">
<xs:include schemaLocation="SimpleModel.xsd"/>
<xs:element name="TestMethod">
<xs:complexType>
<xs:sequence>
<xs:element name="APayload" type="PayloadType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="TestMethodResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="Output" type="PayloadType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Simple.wsdl
<!--WSDL generated by thinktecture WSCF; version 1.0.13.0-->
<!--Tuesday, 09-10-2012 - 02:41 PM-->
<definitions xmlns:tns="urn:test-com:simple" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" name="Simple" targetNamespace="urn:test-com:simple">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
<types>
<xsd:schema>
<xsd:import schemaLocation="SimpleMessages.xsd" namespace="urn:test-com:simple"/>
</xsd:schema>
</types>
<message name="testMethodIn">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
<part name="parameters" element="tns:TestMethod"/>
</message>
<message name="testMethodOut">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
<part name="parameters" element="tns:TestMethodResponse"/>
</message>
<portType name="SimpleInterface">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
<operation name="TestMethod">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"/>
<input message="tns:testMethodIn"/>
<output message="tns:testMethodOut"/>
</operation>
</portType>
<binding name="BasicHttpBinding_SimpleInterface" type="tns:SimpleInterface">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="TestMethod">
<soap:operation soapAction="urn:test-com:simple:testMethodIn" style="document"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="ISimple">
<port name="NewPort" binding="tns:BasicHttpBinding_SimpleInterface">
<soap:address location="http://localhost:50862/Simple.svc"/>
</port>
</service>
</definitions>
Here's the system.serviceModel section from web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="SimpleServiceBehaviour">
<serviceMetadata externalMetadataLocation="http://localhost:50862/TestContract/Simple.wsdl" httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics>
<messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true"/>
</diagnostics>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_SimpleInterface" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="SimpleServiceBehaviour" name="SimpleContract.Simple">
<endpoint address="http://localhost:50862/Simple.svc" behaviorConfiguration="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SimpleInterface" contract="ISimple"/>
</service>
</services>
</system.serviceModel>
If I add a service reference to http://localhost:50862/Simple.svc
Every appears to generate OK.
I create this in the client app.config using the service config editor by importing the web.config:
<system.serviceModel>
<client>
<endpoint address="http://localhost:50862/Simple.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_SimpleInterface" contract="SI.SimpleInterface" name="NewPort"/>
</client>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_SimpleInterface" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
And if I run my test code:
static void Main(string[] args)
{
SimpleInterfaceClient client = new SimpleInterfaceClient();
var ret = client.TestMethod(new PayloadType() { AnInt = 7, AString = "bob" });
Console.WriteLine(ret.ToString());
Console.ReadLine();
}
Inside the TestMethod proxy the following line:
return base.Channel.TestMethod(request);
Throws the following exception
System.ServiceModel.ActionNotSupportedException occurred
Message="The message with Action 'urn:test-com:simple:testMethodIn' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None)."
Source="System.ServiceModel"
StackTrace:
at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
Can anybody help?
Thanks,
J.
First Edit
OK, I've now found that there is something going wrong with my doc-lit-wrapped wsdl and the code generators. wscf.blue does not like it's messages to have nullable types marked as nillable. It falls out of wrapped mode and the method implementations are not unwrapped.
But, if I don't mark them as nillable, the client code falls out of wrapping mode because they are nullable types not marked as nillable.
With nullable types marked not nillable:
Server side:
[System.ServiceModel.OperationContractAttribute(Action="urn:test-com:simple/ISimple/TestMethod", ReplyAction="urn:test-com:simple/ISimple/TestMethodResponse")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
[return: System.ServiceModel.MessageParameterAttribute(Name="Output")]
PayloadType TestMethod(PayloadType APayload);
Client Side:
// CODEGEN: Generating message contract since element name APayload from namespace urn:test-com:simple is not marked nillable
[System.ServiceModel.OperationContractAttribute(Action="urn:test-com:simple:testMethodIn", ReplyAction="*")]
DesktopClientTest_ServiceReference.SI.TestMethodResponse TestMethod(DesktopClientTest_ServiceReference.SI.TestMethodRequest request);
With nullable types marked as nillable:
Server side:
// CODEGEN: Parameter 'Output' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
[System.ServiceModel.OperationContractAttribute(Action="urn:test-com:simple/ISimple/TestMethod", ReplyAction="urn:test-com:simple/ISimple/TestMethodResponse")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
[return: System.ServiceModel.MessageParameterAttribute(Name="Output")]
TestMethodResponse TestMethod(TestMethodRequest request);
Client side:
[System.ServiceModel.OperationContractAttribute(Action="urn:test-com:simple:testMethodIn", ReplyAction="*")]
[return: System.ServiceModel.MessageParameterAttribute(Name="Output")]
DesktopClientTest_ServiceReference.SI.PayloadType TestMethod(DesktopClientTest_ServiceReference.SI.PayloadType APayload);
However I have no idea whether that's the cause, let alone how to fix it. That said, I do know that nullable types should be marked nillable for doc-lit-wrapped wsdl.
I think the problem is contract. In client generated, you can see contract="SI.SimpleInterface", but in service definition contract="ISimple".