WCF双工服务通道关闭

5

我有一个基于WCF双工服务的应用程序。当用户“重新启动”应用程序时,我遇到了问题...在幕后,客户端关闭与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
    }
}

异常信息是" ServiceHost 关闭操作在 00:00:30 后超时。这可能是因为客户端未能在所需时间内关闭会话通道。分配给此操作的时间可能是较长超时的一部分。"。没有内部异常。

谢谢


尝试添加一个OnClose事件处理程序。查看该事件是否在callback服务器端被触发。 - mrtig
谢谢,我刚试了一下:关闭和已关闭事件都被触发了。 - MrShoes
但服务仍然超时了吗?您尝试设置绑定上的“CloseTimeout”了吗? - mrtig
是的,我已经在两端设置了closeTimeout,但仍然出现相同的问题。 - MrShoes
请问您能否发布异常信息?另外,提高应用程序的响应速度的一个快速解决方案是这样做:Task.StartNew(()=>{_context.Close();}); - mrtig
显示剩余4条评论
4个回答

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>

0

你尝试过使用 receiveTimeout="infinite" 吗?看看是否仍然会出现错误。也许你会发现超时并不是导致错误的原因。你有没有考虑创建一个基础客户端类,自动保持连接直到物理关闭呢?


0

猜测可能是由于使用了ConcurrencyMode.Single而导致死锁。

可能发生的情况是,服务器在处理原始请求时尝试回调客户端(或反之亦然)。因此,服务器正在尝试回调客户端,但客户端正在阻塞,因为它仍在等待来自服务器的响应。嘿,就这样,死锁并最终超时。

http://msdn.microsoft.com/en-us/library/system.servicemodel.concurrencymode.aspx


0
问题不仅涉及并发,还涉及绑定类型。 确保服务和回调的并发模式是正确方向的一步。但将绑定从netTcpBinding更改为wsDualHttpBinding最终解决了问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接