WCF回调计时器

时间:2011-08-25 14:19:33

标签: c# .net wcf

我在Windows服务中托管了WCF服务。这使用“发布订阅”模式将事件发布到多个订阅者。但是,我发现在一段时间不活动后,连接失败,我得到可靠的会话是错误的。我试图通过更改不活动超时和接收时间设置来解决这个问题,但它没有任何区别。它的驾驶我疯狂是诚实的。

我所提到的解决方案是每隔一段时间“ping”所有订阅者。 (例如超时长度的一半)。

设置这样的“ping”的最佳方法是什么?即如何向服务添加计时器以及如何使该计时器调用ping函数?

修改

我对ping解决方案并不完全满意,并且想进一步调查为什么我的可靠会话会暂时超时。以下是此服务的绑定配置

服务器app.config

<binding name="WSDualHttpBinding_IError" receiveTimeout="24.20:31:23.6470000">
    <reliableSession inactivityTimeout="24.20:31:23.6470000" />
</binding>

客户端app.config

<binding name="WSDualHttpBinding_IError" closeTimeout="00:01:00"
    openTimeout="00:01:00" receiveTimeout="24.20:31:23.6470000"
    sendTimeout="00:01:00" 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="24.20:31:23.6470000" />
    <security mode="Message">
        <message clientCredentialType="Windows" negotiateServiceCredential="true"
            algorithmSuite="Default" />
    </security>
</binding>

我试过“无限”而不是这个值,但它不喜欢它。虽然谷歌搜索的几个页面建议这样做,但该值无效。我只能假设这在早期版本的WCF / .NET中是有效的

EDIT2:

这是异常日志。它肯定似乎是一个随机的时间。

************** Exception Text **************
System.TimeoutException: The operation did not complete within the allotted timeout of 00:00:59.4979498. The time allotted to this operation may have been a portion of a longer timeout.

Server stack trace: 
   at System.ServiceModel.Channels.InterruptibleWaitObject.Wait(TimeSpan timeout, Boolean throwTimeoutException)
   at System.ServiceModel.Channels.ReliableInputConnection.Close(TimeSpan timeout)
   at System.ServiceModel.Channels.ReliableDuplexSessionChannel.OnClose(TimeSpan timeout)
   at System.ServiceModel.Channels.ClientReliableDuplexSessionChannel.OnClose(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.OnClose(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
   at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
   at System.ServiceModel.ClientBase`1.Close()
   at MyApp.Form1.buttonError_Click(Object sender, EventArgs e)
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

1 个答案:

答案 0 :(得分:2)

要实施ping客户端,您可能需要按照以下步骤列出:

  1. 使用Ping方法扩展回调合约(你应该已经有一个回调合约,因为你写的是你使用发布订阅模式,不是吗?):

    [OperationContract]
    void Ping();
    
  2. 在连接后客户端首先调用的操作中,存储对集合中客户端操作上下文的引用:

    List<OperationContext> _clientCtxList = new List<OperationContext>();
    
    void IMyService.InitSession() {
        _clientCtxList.Add(OperationContext.Current);
    }
    
  3. 定义一个函数,由您的计时器调用以ping所有客户端:

    void tmrPing (object state) {
        foreach (var ctx in _clientCtxList)
        {
            // todo: catch exceptions and remove client context 
            //       from list in case of failure
            ctx.GetCallbackChannel<IMyCallbackContract>().Ping();
        }
    
        // restart timer
        _timer.Change(10000, Timeout.Infinite);
    }
    
  4. 在服务启动时定义并启动计时器(我不知道IIS托管,所以你必须自己找到合适的位置):

    System.Threading.Timer _timer;
    
    void Startup() {
        // call my function in 10 seconds
        _timer = new System.Threading.Timer(
                        tmrPing, null, 10000, Timeout.Infinte);
    }
    
  5. 备注:

    • 这是记事本代码 - 它可能包含语法错误,可能无法编译。
    • 不包括异常处理
    • 不包括_clineCtxList的锁定,但强烈推荐