Web Solutions/Intranets

Using using? Never say never

This is a repost from my personal site:

I was having a discussion with a colleague of mine regarding use of the using statement as it applies to WCF calls. I always wrap using statements around any IDisposable (except in a few cases, like instantiating the Unity container instance for the application). It turns out that this is sometimes wrong, which has caused some developers to suggest that it is always wrong. Interestingly, there is a way to make it always right.
When is use of using dangerous?
In the book Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition), the authors give the following advice when implementing IDisposable:
AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).
Unfortunately for us using fanatics, there are situations where exceptions are thrown from a call to Dispose, perhaps the most famous of which is System.ServiceModel.ClientBase<TModel>, which serves as the base class for all WCF Client Proxy classes generated by the ServiceModel Metadata Utility Tool (Svcutil.exe). MSDN also has a article on "Avoiding Problems with the Using Statement" where the suggestion is to not use the using statement when Dispose() can throw.
 
But using makes my code look pretty!
 
Have no fear, there is a solution! Marc Gravell has a post where he discusses how some extension method magic can be used to still allow us to use our using statements even in these scenarios. I was unable to get some of the code on the post to work as-is, but I took that as an opportunity to enhance the sample with an implementation of the Dispose Pattern which is discussed on the MDSN "Implementing a Dispose Method" article .
 
Step 1: The wrapper interface – improved.
 
This is nearly verbatim from Marc’s Post, with a little addition of the ExceptionHandler action. Since any exceptions thrown by calling Dispose on BaseObject (the underlying IDisposable instance) will be suppressed, this approach has gathered a small amount of criticism. Generally the criticism is not enough to prevent its validity and usefulness in practice; nevertheless the ExceptionHandler has been added to allow any calling code to supply an Action to be taken when an exception is thrown. The only downside that remains is that it is not possible to maintain the call stack in the exception details in the event that we want to re-throw the Exception.
 
/// <summary>
/// Handles something we want to dispose but which might blow up on us.
/// </summary>
/// <typeparam name="T">A type that likes to blowup during dispose</typeparam>
public interface IDisposableWrapper<T> : IDisposable
{
  T BaseObject { get; }
  Action<Exception> ExceptionHandler { get; set; }
}
 
Step 2: The wrapper implementation:
 

/// <remarks>
/// This class not only implements IDisposableWrapper but also serves as an implementation of the BaseDisposable pattern.
/// </remarks>
public class DisposableWrapper<T> : IDisposableWrapper<T> where T : class, IDisposable
{
    public T BaseObject { get; private set; }
    public DisposableWrapper(T baseObject) { BaseObject = baseObject; }
    public Action<Exception> ExceptionHandler { get; set; }
    private bool disposed = false;
    /// <summary>
    /// The default implementation for a DisposableWrapper.
    /// </summary>
    /// <param name="disposing">true if being called from Dispose(), false if being called from a Finalizer</param>
    protected virtual void Dispose(bool disposing)
    {
        if (disposed) return;
        if (disposing)
        {
            if (BaseObject != null)
            {
                try
                {
                    OnDispose();
                }
                catch(Exception e)
                {
                    if (ExceptionHandler != null)
                    {
                        ExceptionHandler(e);
                    }
                } // swallow…
            }
            disposed = true;
        }
    }
    protected virtual void OnDispose()
    {
        BaseObject.Dispose();
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

 
Step 3: A DisposableWrapper just for our ClientBase
 
The Expected Exceptions article on MSDN states:
Code that calls a client communication method must catch the TimeoutException and CommunicationException. One way to handle such errors is to abort the client and report the communication failure.

public class ClientWrapper<TProxy> : DisposableWrapper<TProxy>
    where TProxy : class, IDisposable, ICommunicationObject
{
    public ClientWrapper(TProxy proxy) : base(proxy) { }
    /// <summary>
    /// specific handling for service-model
    /// </summary>
    protected override void OnDispose()
    {
        if (BaseObject.State == CommunicationState.Faulted)
        {
            BaseObject.Abort();
        }
        else
        {
            try
            {
                BaseObject.Close();
            }
            catch (TimeoutException)
            {
                BaseObject.Abort();
            }
            catch (CommunicationException)
            {
                BaseObject.Abort();
            }
            catch
            {
                BaseObject.Abort();
                throw;
            }
        }
    }
}

Step 4: Extension Methods:
 
This is one part where Marc’s code didn’t exactly work for me. For some reason, the extension method for disposing the ClientBase<T> was not able to be called without a cast. I took advantage of having to rewrite the extension method to change the interface of the method to loosen the restrictions on type T to be IDisposable and an ICommunicationObject instead of only for ClientBase.
 

public static class WCFExtensions
{
    // core "just dispose it without barfing"
    public static IDisposableWrapper<T> Wrap<T>(this T baseObject)
        where T : class, IDisposable
    {
        return baseObject as IDisposableWrapper<T> ?? new DisposableWrapper<T>(baseObject);
    }
    // specific handling for service-model
    public static IDisposableWrapper<T> WrapProxy<T>(this T proxy)
        where T : class, IDisposable, ICommunicationObject
    {
        return new ClientWrapper<T>(proxy);
    }
}

Step 5: Use using safely:
 
Now we can safely wrap our code in a using statement:
 
using(var clientWrapper = new MyWcfServiceClient().WrapProxy())
{
    clientWrapper.ExceptionHandler = ex =>
    {
        Logger.LogError(ex);
    }
    var response = clientWrapper.BaseObject.PerformAction();
}

 

Tags:, ,

Leave a Reply