我有一个基于WCF Duplex服务的应用程序。用户"重新启动"应用程序的工作......在幕后,客户端关闭与WCF服务的连接并创建另一个。服务合同的定义如此......
[ServiceContract(Namespace="net.tcp://namespace.MyService",
SessionMode=SessionMode.Required,
CallbackContract=typeof(IServiceCallback))]
public interface IMyService
{
[OperationContract(IsOneWay=true)]
void DoWork();
}
public interface IServiceCallback
{
[OperationContract(IsOneWay=true)]
void SendMessage(string message);
}
实施定义为:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single,
InstanceContextMode = InstanceContextMode.PerSession,
UseSynchronizationContext = false,
IncludeExceptionDetailInFaults = true)]
public class MyService : IMyService
{
public void DoWork()
{
var callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
callback.SendMessage("Hello, world.");
}
}
客户端的配置如下:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="net.tcp" receiveTimeout="02:00:00" sendTimeout="02:00:00" maxReceivedMessageSize="2147483647">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:8000/MyService/MyService"
binding="netTcpBinding" bindingConfiguration="net.tcp" contract="ExternalServiceReference.IMyService">
</endpoint>
</client>
</system.serviceModel>
配置服务:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehaviour">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="netTcp" sendTimeout="01:00:00" receiveTimeout="01:00:00" >
<security mode="None">
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="serviceBehaviour" name="MyService.MyService">
<endpoint address="MyService" binding="netTcpBinding" bindingConfiguration="netTcp" name="net.tcp" contract="MyService.IMyService" />
<endpoint binding="mexTcpBinding" bindingConfiguration="" name="net.tcp" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8000/MyService" />
</baseAddresses>
</host>
</service>
</services>
在客户端的构造函数中:
var callback = new CallbackImplementation();
_context = new InstanceContext(callback);
_proxy = new MyServiceProxy(_context);
我在建立新连接之前尝试以下操作:
try
{
if (_context != null)
{
_context.ReleaseServiceInstance();
_context.Close();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
if (_context != null)
{
_context.Abort();
}
}
我看到的问题是_context.Close()调用总是超时并抛出异常。虽然我当时正在中止频道,但这对我来说感觉不对,而且我认为这是我申请中冻结的原因。有人知道为什么Close()调用会失败吗?
编辑:我之前错过了一些可能与我的回调实施有关的内容。它看起来像这样:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Single,
UseSynchronizationContext = false,
IncludeExceptionDetailInFaults = true)]
public class CallbackImplementation : IServiceCallback
{
public void SendMessage(string message)
{
// Do something with the message
}
}
异常消息是&#34; ServiceHost关闭操作在00:00:30后超时。这可能是因为客户端未能在所需时间内关闭会话通道。分配给此操作的时间可能是较长超时的一部分。&#34;。没有内在的例外。
由于
答案 0 :(得分:1)
我没有立即看到问题,但我经常发现在客户端和服务器上运行跟踪并检查结果通常会指向我的解决方案。将它放在.config文件(客户端和服务器)中,确保路径指向存在的文件夹。运行您的应用程序,获取失败,然后关闭所有内容并运行SvcTraceViewer.exe以读取结果。
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information,ActivityTracing"
propagateActivity="true">
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\logs\TracingAndLogging-service.svclog" type="System.Diagnostics.XmlWriterTraceListener"
name="xml" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
答案 1 :(得分:0)
您是否尝试过receiveTimeout =“infinite”,看看是否仍然收到错误。您可能只是发现创建错误的超时不是。您是否考虑过创建一个基本客户端类来自动保持连接活动直到物理关闭?
答案 2 :(得分:0)
猜测,这可能是因使用ConcurrencyMode.Single
而造成的死锁。
可能发生的是服务器在处理原始请求时尝试回叫客户端(反之亦然)。因此服务器正在尝试回调客户端,但客户端正在阻塞,因为它仍在等待来自服务器的响应。嘿presto,僵局,最终暂停。
http://msdn.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx
答案 3 :(得分:0)
问题不仅是并发,而是绑定类型。
确保服务和回调的并发模式是朝着正确方向迈出的一步。但是将绑定从netTcpBinding更改为wsDualHttpBinding最终解决了问题