Duplex communication using NetTcpBinding - ContractFilter mismatch?
I'm making slow and steady progress towards having a duplex communication channel open between a client and a server, using NetTcpBinding. (FYI, you can observe my newbie progress here and here!)
I'm now at the stage where I have successfully connected to my server, through the server's firewall, and the client can make requests of the server.
In the other direction, however, things aren't quite so happy. It works fine when testing on my own machine, but when testing over the internet, when I try to initiate a callback from the server side, I get an error:
The message with Action 'http://MyWebService/IWebService/HelloWorld' 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).
Here are some of the key bits of code. First, the web interface:
[ServiceContract(Namespace = "http://MyWebService", SessionMode = SessionMode.Required, CallbackContract = typeof(ISiteServiceExternal))]
public interface IWebService {
[OperationContract]
void Register(long customerID);
}
public interface ISiteServiceExternal {
[OperationContract]
string HelloWorld();
}
Here's the implementation of IWebService:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class WebService : IWebService {
void IWebService.Register(long customerID) {
Console.WriteLine("customer {0} registering", customerID);
var callbackService = OperationContext.Current.GetCallbackChannel<ISiteServiceExternal>();
RegisterClient(customerID, callbackService);
Console.WriteLine("customer {0} registered", customerID);
}
}
Then, on the client side (I was fiddling with these attributes without really knowing what I'm doing):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, Namespace="http://MyWebService")]
class SiteServer : IWebServiceCallback {
string IWebServiceCallback.HelloWorld() {
return "Hello World!";
}
...
}
So what am I doing wrong here?
EDIT: Adding app.config code. From server:
<system.serviceModel>
<diagnostics>
<messageLogging logMalformedMessages="true" logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true" logEntireMessage="true" maxMessagesToLog="1000" maxSizeOfMessageToLog="524288" />
</diagnostics>
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name ="MyWebService.WebService" behaviorConfiguration="mex">
<endpoint address="net.tcp://localhost:8000" binding="netTcpBinding" contract="MyWebService.IWebService"
bindingConfiguration="TestBinding" name="MyEndPoint"></endpoint>
<endpoint address ="mex"
binding="mexTcpBinding"
name="MEX"
contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8000"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="TestBinding" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" portSharingEnabled="false">
<readerQuotas maxDepth="32" maxStringContentLength ="8192" maxArrayLength ="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
and on the client side:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="MyEndPoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false"
transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10"
maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="None">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign">
<extendedProtect开发者_Go百科ionPolicy policyEnforcement="Never" />
</transport>
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://mydomain.gotdns.com:8000/" binding="netTcpBinding"
bindingConfiguration="MyEndPoint" contract="IWebService" name="MyEndPoint" />
</client>
</system.serviceModel>
Kudos to @Allon Guralnek, who helped me notice what was wrong:
On the server side I had:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class WebService : IWebService { ... }
And on the client side I had:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, Namespace="http://MyWebService")]
class SiteServer : IWebServiceCallback { ... }
The conflict was between PerCall
and PerSession
. I just changed the server side to PerSession
, and - Houston, we have lift-off!
Now, to get this working with security... watch SO for the next exciting installment in my WCF learning curve! :)
You listed your callback contract as ISiteServiceExternal
but your client implements IWebServiceCallback
. Fix that first and see if you have success.
精彩评论