It’s a wellknown point of pain for Windows Communication Foundation developers that ClientBase<T> is, in fact, broken.  Though it implements IDisposable, calling Dispose doesn’t clean everything up in all cases.  Instead, you have to close the channel manually (aborting it instead if it is faulted), handle errors, then dispose of it.  I’m not sure why this approach was chosen, but given how obvious the problem is and how much pain it’s caused, I have to think there’s a very good reason it is the way it is.

I set about this weekend to try and fix this problem for the proxies we use at InRAD.  Our proxies all derive from ClientBase<T>, so I thought “Hey, I’ll just make a new base class for our proxies by inheriting from ClientBase<T>!”  For this to work, I knew I’d want my custom base class to implement a new IDisposable.Dispose method which would close/abort the channel, then call ClientBase’s Dispose method.  This turned out to be a lot more complicated than it sounds.

The first part was very easy.  I setup my disposable method like so:

void IDisposable.Dispose()
{
    if (State == CommunicationState.Faulted)
    {
        Abort();
    }
    else
    {
        try
        {
            Close();
        }
        catch
        {
            Abort();
        }
    }
    
    //TODO: Call the base-class Dispose method.
}

If the channel is faulted, it calls Abort, otherwise it tries to call Close, and if that fails, it falls-back and calls Abort again.  Fairly straight-forward, all that remains is to call the base Dispose method.  There’s just one problem.  It is explicitly implemented.   That means you can’t get to it without casting to IDisposable.  And you can’t do ((IDisposable)base).Dispose() as base can’t be used in that way.  You also can’t do ((IDisposable)(ClientBase<T>)this).Dipose(), as that refers to the current Dispose method and not the base class implementation.  Ruh-roh. 

After lots of Googling and lots of “No, you can’t do that” answers, I found a post by Eyal Safran that showed me how to do what I wanted, just not in the way I wanted.  The solution is to use reflection:

void IDisposable.Dispose()
{
    if (State == CommunicationState.Faulted)
    {
        Abort();
    }
    else
    {
        try
        {
            Close();
        }
        catch
        {
            Abort();
        }
    }

    //Call the base-class implementation of IDisposable.Dispose. 
    typeof (ClientBase<TChannel>).GetInterfaceMap(typeof (IDisposable)).TargetMethods[0].Invoke(this, null);
}

So, problem solved, right?  Well, no, not really.  At this point, I thought “Hey, I wonder what that base Dispose method is actually doing?”, so I fired up Reflector (shame on you, redgate, for requiring registration in order to download such an awesome and formerly-noings-attached tool).

It turns out that you don’t even need to call the base class Dispose implementation in this case.  All ClientBase.Dispose is going to do is call Close, which the new Dispose method is going to do anyway, so you can actually omit the reflection and just not call the base Dispose implementation for now.  Who knows if that will be true in future versions of WCF and the framework. 

In any case, the custom proxy base class allows me to combine my proxies with the using statement and get the semantics that I expect, and I now know how to call an explicitly implemented interface from a derived class that also implements the same interface.  Knowledge++;