开发者

WCF Callback Timer

I have a WCF service hosted in a Windows service. This uses the Publish Subscribe pattern to post events to multiple subscribers. However, I am finding that after a length of inactivity, the connection fails and I get reliable session was faulted errors. I have tried to fix this by changing the inactivity timeout and receive timout settings but it makes no difference. It's driving me mad to be honest.

A solution I have seen mentioned is to "ping" all the subscribers every so often. (for example half the length of the timeout).

What would be the best way of setting up a "ping" like this? i.e. how do I add a timer to the service and how to get that timer to call a ping function?

EDIT:

I am not totally happy with the ping solution and would like to investigate further why my reliable session keeps timing out. Below is the binding configuration for this service

Server app.config

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

Client 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" negot开发者_开发知识库iateServiceCredential="true"
            algorithmSuite="Default" />
    </security>
</binding>

I tried "infinite" rather then this value but it didn't like it. Said the value was invalid even though several pages from a Google search suggested doing this. I can only assume this was valid in an earlier version of WCF/.NET

EDIT2:

Here is the exception log. It definitely does seem to be a random amount of time.

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


For implementing the pinging of your clients you may want to follow this list of steps:

  1. Extend your callback contract with a Ping method (you should have already a callback contract because you wrote you use the publish subscribe pattern, havn't you?):

    [OperationContract]
    void Ping();
    
  2. In the operation the clients call first after connecting, store a reference to the clients operation context in a collection:

    List<OperationContext> _clientCtxList = new List<OperationContext>();
    
    void IMyService.InitSession() {
        _clientCtxList.Add(OperationContext.Current);
    }
    
  3. Define a function, called by your timer to ping all the clients:

    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. Define and start a timer when your service starts up (i'm not aware of IIS hosting, so you have to find the right location for this yourself):

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

Remarks:

  • This is notepad code - it might contain syntactic errors and might not compile.
  • Exception handling is not included
  • locking of the _clineCtxList is not included but highly recommended
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜