16

i'm currently trying to set up something like this:

  • a server side windows wcf service hangs out and listens via tcp for connections from a client side windows service.
  • when a connection is received (the client calls the CheckIn method on the service) the service obtains a callback channel via OperationContext.Current.GetCallbackChannel<T>
  • this channel is stored in a collection along with a unique key (specifically, i store the callback interface, the channel, and the key in a List<ClientConnection> where each of those is a property)
  • calls should now be able to be passed to that client service based on said unique key

this works at first, but after a while stops -- i'm no longer able to pass calls to the client. i'm assuming it's because the connection has been dropped internally and i'm trying to work with a dead connection.

that in mind, i've got the following questions:

  • how do i tell wcf i want to keep those tcp connections indefinitely (or for as long as possible)?
  • how do i check, from the client side, whether or not my connection to the server is still valid so i can drop it and check in with the server again if my connection is fried?

i can think of gimpy solutions, but I'm hoping someone here will tell me the RIGHT way.

Joshua Evensen
  • 1,544
  • 1
  • 15
  • 33
  • 1
    Just a bit of info for everyone -- we ended up not using WCF as our solution since we're writing a potentially high traffic server application and there were a lot of things to deal with. We ran into some performance issues, our server app just fell over at some point. Probably fixable, but we ended up using RabbitMQ instead. – Joshua Evensen Nov 27 '13 at 19:49
  • Thanks for the mention of RabbitMQ, I wasn't familiar with that. – PaulF Aug 20 '15 at 15:26

1 Answers1

16

When you establish the connection from the client, you should set two timeout values in your tcp binding (the binding that you will pass to ClientBase<> or DuplexClientBase<>):

NetTcpBinding binding = new NetTcpBinding();
binding.ReceiveTimeout = TimeSpan.FromHours(20f);
binding.ReliableSession.InactivityTimeout = TimeSpan.FromHours(20f);

My sample uses 20 hours for timeout, you can use whatever value makes sense for you. Then WCF will attempt to keep your client and server connected for this period of time. The default is relatively brief (perhaps 5 minutes?) and could explain why your connection is dropped.

Whenever there is a communication problem between the client and server (including WCF itself dropping the channel), WCF will raise a Faulted event in the client, which you can handle to do whatever you feel appropriate. In my project, I cast my DuplexClientBase<> derived object to ICommunicationObject to get a hold of the Faulted event and forward it to an event called OnFaulted exposed in my class:

ICommunicationObject communicationObject = this as ICommunicationObject;
communicationObject.Faulted +=
   new EventHandler((sender, e) => { OnFaulted(sender, e); });

In the above code snippet, this is an instance of my WCF client type, which in my case is derived from DuplexClientBase<>. What you do in this event is specific to your application. In my case, the application is a non-critical UI, so if there is a WCF fault I simply display a message box to the end-user and shut down the app - it'd be a nice world if it were always this easy!

PaulF
  • 1,133
  • 8
  • 14
  • It seems like this is working. I'll let you know how it turns out when I've done testing! – Joshua Evensen Mar 23 '11 at 15:08
  • Can you please explain where to write below code and what to do in OnFaulted event? I mean at client side or at server side where error occurs! ICommunicationObject communicationObject = this as ICommunicationObject; communicationObject.Faulted += new EventHandler((sender, e) => { OnFaulted(sender, e); }); – KomalJariwala Oct 23 '13 at 12:10
  • @KomalJariwala the communicationObject.Faulted event is available on the client side, from your ClientBase-derived object. I edited the answer above to clarify this, and to explain the simple code I could get away with in my own OnFaulted implementation. – PaulF Oct 28 '13 at 21:11
  • But how about the server side faulter? If this happening on client side, I can reconnect again. but server looks like can't reconnect it in Duplex. – qakmak Aug 20 '15 at 14:39
  • @qakmak, I think this is a situation that you have to handle regardless of timeouts. There are many reasons that clients can disappear without telling the server. If the server has something important to tell that client, it will simply have to wait to see if the client reconnects. If the client does reconnect, you can get a hold of a current callback channel. – PaulF Aug 20 '15 at 15:25
  • So you mean, there is no way let server Initiative to reconnect to the client? Only way is let client check the connect? – qakmak Aug 20 '15 at 15:29
  • 1
    There's no way the server COULD reconnect to the client -- unless the client were publicly exposed. – Joshua Evensen Sep 02 '15 at 19:20