IErrorHandler interface is confusing me

292 Views Asked by At

I have created a class that implements IErrorHandler and IServiceBehavior. I add the behavior to my ServiceHost and run it.

The reason I got around to trying to learn about IErrorHandler is because the frustration I was having in having to wrap all of my service code that interfaces with callback channels in try catch statements, and wondered if there was a global way to catch the exceptions.

Well from what I read here on StackOverflow, I saw that it is indeed the thing I want.

In execution however, it's confusing me greatly. If I have a contract method that does the following...

    Dictionary<IChatCallback, string> userChannels = new Dictionary<IChatCallback, string>();

    public void SendMessage(string message)
    {
        IChatCallback callback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
        string senderName = userChannels[callback];

        SendMessageToAllUsers(message, senderName);
    }

    public void SendMessageToAllUsers(string message, string sender)
    {
        foreach (var userChannel in userChannels.Keys)
        {
            userChannel.ReceiveMessage(new ChatMessage(message, sender));
        }
    }

If a client is on my server and he drops off the face of the earth and the channel faults, it seems to take a while before my server realizes that the channel is faulted. Even if am subscribed to the events of the ICommunicationObject, it seems to take a while before the server realizes the channel is faulted. For example, if someone is sending messages and someone disconnects, and a message is being propagated at the same time.

Now, I have another method that essentially pings clients at a regular interval to figure out if they're still there or not, so I can remove them from the userChannel dictionary.

How exactly is IErrorHandler supposed to help me here? It seems that it's not exactly helping my service from crashing even if it catches the error. Because my service cannot ping my clients at a super rapid pace, sometimes a message seems to come in immediately(I was testing this) after a previous message that threw an exception. It seemed to have handled the first one, but the second one threw another exception that wasn't caught, and my service crashed, because the server was trying to communicate with a faulted channel. Now, my service DOES clean up those faulted channels, but it does so periodically.

I was hoping that by implementing IErrorHandler I could avoid having to wrap all of my methods in try{}catch{} blocks... but it seems like I still have to, to check if I'm communicating with a faulted channel?

Or maybe I'm just going about using IErrorHandler improperly and thinking it should be doing things it's not supposed to do. Should I maybe have my service implement it, and inject itself into the Servicehost as the IServiceBehavior? And then in my HandleError() method remove the channel from my list of clients? That seems kind of messy, because I'm putting that WCF plumbing stuff in my service class, but that would be the only way I can think of to have the exception code itself remove the channel from the list of callbacks.

I'm trying to do a lot of reading because I'm new to it, but it seems like the world of Error Handling in WCF is daunting.

Even if I try to remove the channel so it's not called on services via subscribing to the Faulted event, it doesn't work fast enough and still throws exception that the server cannot seem to recover from even with IErrorHandler.

For example, when the user first connects, I subscribe to the event.

        IChatCallback callback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
        ICommunicationObject callbackComm = (ICommunicationObject) callback;
        callbackComm.Faulted += (sender, e) =>
            {
                lock (lockObject)
                {
                    string name = userChannels[callback];
                    userChannels.Remove(callback);
                    NotifyOfUserDisconnect(name);
                }
            };

Do I just need to go into all my methods and check if the channel is closed or faulted, and wrapping everything in a try/catch block to remove the reference and notify clients?

0

There are 0 best solutions below