I have a WCF self-hosted service with a net.tcp DuplexChannel. On the server I run the following to disconnect a client:
((ICommunicationObject)client.CallbackChannel).Close();
This works fine but how do I detect on the client that it has been disconnected?
Ive hooked up to Closed and Faulted-events on both the InstanceContext of the callback and the channel to the server:
InstanceContext callback = new InstanceContext(callbackImp);
callback.Closed += new EventHandler(callback_Closed);
and
((ICommunicationObject)Channel).Closed += new EventHandler(Channel_Closed);
But nothing works. I never get notified. The workaround Im using now is to have a method in the callback that triggers a disconnect from the client-side instead. But I rather not do it this way. I especially dont want to let the server wait for a user to disconnect.
EDIT
I just realized that when disconnecting from client-side I run a method in the service-contract which is marked with IsTerminating = true:
[OperationContract(IsTerminating = true)]
void Disconnect();
I figured it would be the same on the callback-contract then? I tried adding the same method to my callback and it did terminate the callback-channel from the server point of view but I still didnt got notified on the client-side...weird
EDIT
I found out some more info about this:
When the server aborts the callback
channel, a fault travels back to the
client, the client faults and we get
the Faulted event on the client.
When the server closes the callback
channel, the session is still open
until the client issues the close.
Once the client closes the channel
you'll see the Closed event.
According to this statement the Close-event is not triggered mearly by closing the callbackchannel from the server, the client has to close it as well. So I could run Close on the client in the terminating Disconnect-method of the callback. Or I could use the Abort-method on the callback server-side and skip using a Disconnect-method on the callback. I dont know which one I preffer honestly. Hmmmm.
EDIT
I went with the Abort-approach. It seemed like the most logical method and it works really well. The client gets notified with the Faulted-event on the callback-instancecontext. Nice.
I went with the Abort-approach. It seemed like the most logical method and it works really well. The client gets notified with the Faulted-event on the callback-instancecontext.
You can simply do a callback just before closing the callback channel telling the client you're closing the channel.
So just before this line of code:
((ICommunicationObject)client.CallbackChannel).Close();
Related
We have (Multiple)Clients-(One)Server architecture for poker desktop game. We are using callback Notifications using callback Channels.
But sometimes because of internet connection drops, that particualr client gets disconected from server and that particular's client's WCF channel is also gone to faluted state and his callback Channel which lies in server is also faluted.
Scenario :
That client is playing game, while internet connection drops, that game is stopped, still his game window remains open and when his/her internet connection gets back that client is dropped out from Server, but that player's game window still opens and that player can't do anything as his/her WCF channel is dropped out.
We want to close that particular client's window while he/she is dropped out from server and throwing 'CommunicationObjectAbortedException ' exception.
We can't use previous WCF channel's callback channel as it's in faluted state.
So we have tried to create new callbackChannel in server while dropping using below code :
OperationContext.Current.GetCallbackChannel();
but here Current is showing "NULL" as that player's WCF channel is aborted, so it's throwing an error that "Object reference not set to an instance of object".
So is there any solution to use aborted WCF channel's callback Channel or recover that WCF channel without reinitializing them or to call that client using new channel?
I'd try following:
On server side, when trying to communicate using faulted / aborted chanel - you'll failed.
Catch this failure, and remove its callback from the list (I suppose you manage some callback list).
On client side - when chanel Faulted / ... handled - try to re-open new chanel to server. When this new chenel will be open, on server side place this new callback back to the "valid callbacks" list.
I was looking at Microsoft's duplex WCF sample:
It starts here but the interesting bit is here at the end with the client.
// Wait for callback messages to complete before
// closing.
System.Threading.Thread.Sleep(5000);
// Close the WCF client.
wcfClient.Close();
Console.WriteLine("Done!");
If you take out the Sleep, you will get an exception
The session was closed before message transfer was complete.
So clearly the client knows there's stuff in the air, is there a way to ask it for its current status? There's a state but that just defines whether it's open or closed (i.e. connected not active).
This is not entirely true. Your methods are one-way method calls. So, when you call the service from your client, that call (or set of calls) is completed. In other words, the "message" has been delivered to the service and there is no expectation for a response since it is one-way. It might callback on the callback contract...it might not.
When you setup Duplex channel, you're standing up an endpoint for the service to call back on (client becomes a service essentially). If you close the client, then if/when the service decides to call back, the communication exception will occur. That's just the way this message exchange pattern works.
You really sort of answered your own question. Which is, when you check the status it is either open, closed (or faulted). When you're using a duplex channel, open in this case means there is potentially "activity" on the channel. That's why the sleep is there - to allow the service time to call back. If you look at the SDK sample (http://msdn.microsoft.com/en-us/library/vstudio/ms752216(v=vs.110).aspx), it's basically doing the same thing except it sits there waiting for you to press ENTER before it closes the client application.
So, in a real application (not a console based sample like these are), either keep your client proxy active or change your message exchange pattern to a request/reply pattern.
I have fully working duplex messaging solution for Silverlight application. Now I would like to add one feature to it. When user leaves the application I want to notify the server about that by sending the last message before exit.
I have tried to send duplex message during Application Exit event, but DuplexServiceClient is already in CommunicationState.Faulted state.
I've also tried to establish new connection and send the message. Everything seemed to be okay on the client side, but no message has been send at all. I checked that twice by using Fiddler.
App.Current.Exit += (s, e) =>
{
var dsc = new DuplexServiceClient(_binding, new EndpointAddress("../Services/MyService.svc"));
dsc.SendToServiceAsync(new UserLeave());
};
Crucial thing is, that I need to notify the server immediately after user leaves the application, so timeouts or similar workarounds are not good enough for me in this situation.
Does anybody have a working solution?
I found similar topic here in SO. Aliostad's answer made me think about this once more. You can never be sure you will get the signal from client that he's leaving. So I ended up with timeout solution.
Just trying to get my head around what can happen when things go wrong with WCF. I have an implementation of my service contract declared with an InstanceContextMode of PerSession...
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
The calls happen as follows:
My client calls the server and calls GetServerUTC() to return the current UTC time of the server. This is a one way call and the server will call the client back when its ready (trivial in this instance to simply return the current time!)
The server calls back to the client and for test purposes in the callback implementation on the client I throw an exception.
This goes unhandled in the client (for test purposes) and the client crashes and closes down.
On the server I handle the faulted event handler on the ICommunicationObject...
obj.Faulted += new EventHandler(EventService_Faulted);
Questions...
Will this kill off the session for the current connection on the server.
I presume I am free to do what I want in this method e.g. logging or something, but should I do anything specific here to terminate the session or will WCF handle this?
From a best practise view point what should I do when the callback is faulted? Does it mean "something has happened in your client" and thats the end of that or is there something I a missing here?
Additionally, are there any other faulted handlers I should be handling.
Ive done a lot of reading on WCF and it seems sort of vague on what to do when something goes wrong. At present I am implementing a State Machine on my client which will manage the connection and determine if a user action can happen dependant on if a connection exists to the server - or is this overkill.
Any tips would be really appreciated ;)
I found out that the session will time out as per the settings for your sessions. Strangely I noticed that once faulted the client is still able to call other methods on the same session.
I have a publish/subscribe scenario in WCF using net.tcp and Duplex callbacks. I have a number of clients that subscribe to the service, and this works fine. However, sometimes a client will close without unsubsribing (Client computer goes to sleep, computer crashes, network connection is aborted, etc..), this causes an exception to be thrown when I callback via my callback list.
Now, I can certainly catch the exception and remove the offending callback, but this seems less like an exception scenario to me and further along the lines of "expected behavior".
Is there an event that gets fired on connection close that will notify me so that I can remove the callback from my list? Consider that this is net.tcp and not HTTP, so connection state should be known.
Clearly the framework knows the connection has been closed and disposed because the exception is something along the lines of "attempt to call a disposed object".
EDIT:
I should point out, that this is not a long running transaction. It's a long running connection in a publish/subscribe scenario. Basically, the callback is used to notify transient subscribers of various events as they happen. Each event is isolated and not long running.
It has been a while, this is from memory so I could be wrong, but I think perhaps if you make an IEndpointBehavior that goes an pokes at the DispatchRuntime to add an IInputSessionShutdown, then you can get notified when the session channel ends.
http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.dispatchruntime.inputsessionshutdownhandlers.aspx