gpt4 book ai didi

c# - WCF 回调计时器

转载 作者:太空宇宙 更新时间:2023-11-03 11:32:58 25 4
gpt4 key购买 nike

我在 Windows 服务中托管了一个 WCF 服务。这使用发布订阅模式将事件发布到多个订阅者。但是,我发现在一段时间不活动后,连接失败并且我收到 reliable session was faulted 错误。我试图通过更改不活动超时和接收超时设置来解决此问题,但这没有任何区别。老实说,这让我发疯。

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

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

编辑:

我对 ping 解决方案不是很满意,想进一步调查为什么我的可靠 session 总是超时。下面是这个服务的绑定(bind)配置

服务器应用程序配置

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

客户端应用配置

<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>

我试过“无限”而不是这个值,但它不喜欢它。表示该值无效,尽管来自 Google 搜索的多个页面建议这样做。我只能假设这在早期版本的 WCF/.NET 中有效

编辑 2:

这是异常日志。它看起来确实是一个随机的时间量。

************** 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)

最佳答案

要实现客户端的 ping,您可能需要遵循以下步骤:

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

    [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);
    }

备注:

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

关于c# - WCF 回调计时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7191993/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com