Why is my WCF client timing out after calling a method in the WCF server that raises an event?
I have a WCF service hosted within a Windows service. There is s method in the WCF service that will raise an event that the Windows service subscribes to. When the event is raised and the Windows service catches it, the Windows service calls another WCF method to send a message to all connected clients. For some reason when I have all these these happen in this sequence an error is thrown:
This request operation sent to http://localhost:8731/Design_Time_Addresses/WCF/WCFService/ did not receive a reply within the configured timeout (00:00:29.9939996)....
Here is the relevant code from teh WCF service:
public event EventHandler<CustomEventArgs> CustomEvent;
private static readonly List<IMessageCallback> subscribers = new List<IMessageCallback>();
public void SendMessageToClients(string msgType, string message)
{
subscribers.ForEach(delegate(IMessageCallback callback)
{
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
callback.OnMessageReceived(msgType, message, DateTime.Now);
}
else
{
subscribers.Remove(callback);
}
});
}
public bool messageHost()
{
try
{
if (CustomEvent != null)
CustomEvent(null, new CustomEventArgs());
return true;
}
catch
{
return false;
}
}
And the Code from the Windows service:
wcfService = new WCF.WCFService();
sHost = new ServiceHost(wcfService);
wcfService.CustomEvent += new EventHandler<WCF.CustomEventArgs>(wcfService_CustomEvent);
sHost.Open();
private void wcfService_CustomEvent(object source, WCF.CustomEventArgs e)
{
wcfService.SendMessageToClients("log", "CLient connected!!");
osae.AddToLog("client message"); //just writes to a log file
}
And the client just calls this:
wcfObj.messageHost();
Here is the client config:
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IWCFService" closeTimeout="00:00:10"
openTimeout="00:00:10" receiveTimeout="00:10:00" sendTimeout="00:00:30"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" />
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8731/Design_Time_Addresses/WCF/WCFService/"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IWCFService"
contract="WCFService.IWCFService" name="WSDualHttpBinding_IWCFService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
And the service config:
<system.serviceModel>
<services>
<service name="WCF.WCFService" behaviorConfiguration="WCFBehavior">
<endpoint address="" binding="wsDualHttpBinding" contract="WCF.IWCFService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint
address="mex"
binding="mexHttpBinding"
bindingConfiguration=""
contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8731/Design_Time_Addresses/WCF/WCFService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior nam开发者_如何学编程e="WCFBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
If I remove the SendMessageToClients call from the event in the Windows service it works and just logs the 'client message' as expected. Also, when the error is thrown about the timeout I can click continue and the the client continues to run and it received the message from the host. Why is the strange behavior happening?
EDIT: Marc led me to search in the right place: http://www.codeproject.com/KB/WCF/WCF_Duplex_UI_Threads.aspx
The symptoms here suggest to me like there is a deadlock happening, perhaps due to a sync-context (WCF respects sync-context by default). Meaning: the outward message is waiting on access to the context, but it is itself the thing that the existing context is waiting on.
The easiest way to investigate that would be to perform the outward message on a worker thread:
ThreadPool.QueueUserWorkItem(delegate {
wcfObj.messageHost();
});
I believe you can also configure WCF to change how it approaches sync-context, but I can't remember how...
精彩评论