다음을 통해 공유


Tales from the Trenches: Using Unity

patterns & practices Developer Center

On this page: Download:
Case study provided by Luke Sigler and edited by Julián Domínguez

Download code

Download PDF File

Order Paperback

Case study provided by Luke Sigler

My first exposure to Unity was a number of years ago. It was consistently presented to me as “something we should use to help with testing” by other developers. It seemed like a good idea in practice, but it was never something that was really pushed. In fact, it seemed like most developers would go out of their way to avoid using it due to the perceived difficulty of setting it up. Eventually, I stopped looking for places to inject it. No pun intended.

But after serving on the Advisory Board for Unity 3, I was determined to once again look for opportunity in which to use it responsibly.

While working on bringing up a collection of OData-enabled ASP.NET Web API services querying a Database-First Entity Framework implementation, it struck me as fantastic place to use it for disposing my DbContexts.

When executing a LINQ-to-entities statement when using an OData enabled method, a standard using statement, like-so, will not work as the DbContext will be closed before the OData query attempts to apply itself.

public class ProductsController : OdataController
{
    [HttpGet]
    [Queryable]
    public IQueryable<ProductRestObject> Get()
    {
        var manager = new ProductsManager();

        return manager.GetProducts();
    }
}

public class ProductsManager
{
    public IQueryable<ProductRestObject> GetProducts()
    {
        using (var context = new ProductsContext())
        {
            return context.Ef_Products
                .Select(product =>
                    new ProductRestObject()
                    {
                        Id = product.ProductId,
                        Name = product.ProductName,
                        Price = product.ProductPrice
                    });
        }
    }
}

Simply removing the using statement alone was unwise so I decided to have the ProductsManager class handle disposing of the context manually.

public class ProductsManager : Idisposable
{
    public ProductsContext CurrentProductsContext { get; set; }

    public ProductsManager()
    {
        CurrentProductsContext = new ProductsContext();
    }

    public IQueryable<ProductRestObject> GetProducts()
    {
        return CurrentProductsContext.Ef_Products
            .Select(product =>
                new ProductRestObject()
                    {
                        Id = product.ProductId,
                        Name = product.ProductName,
                        Price = product.ProductPrice
                    });
    }

    public void Dispose()
    {
        CurrentProductsContext.Dispose();
    }
}

public class ProductsController : OdataController
{
    public ProductsManager CurrentProductsManager { get; set; }
    [HttpGet]
    [Queryable]
    public IQueryable<ProductRestObject> Get()
    {
        CurrentProductsManager = new ProductsManager();

        return CurrentProductsManager.GetProducts();
    }

    protected override void Dispose(bool disposing)
    {
        CurrentProductsManager.Dispose();
    }
}

But that was just plain sloppy. This is when it occurred to me that Unity would work great here. After getting the Unity WebApi Bootstrapper package from NuGet, I changed it up a bit.

public interface IProductsDataSource: Idisposable
{
    IQueryable<ProductRestObject> GetProducts();
}

public class ProductsManager : IproductsDataSource
{
    public ProductsContext CurrentProductsContext { get; set; }
    public ProductsManager()
    {
        CurrentProductsContext = new ProductsContext();
    }

    public IQueryable<ProductRestObject> GetProducts()
    {
        return CurrentProductsContext.Ef_Products
            .Select(product =>
                new ProductRestObject()
                    {
                        Id = product.ProductId,
                        Name = product.ProductName,
                        Price = product.ProductPrice
                    });
    }

    public void Dispose()
    {
        CurrentProductsContext.Dispose();
    }
}

public class ProductsController : OdataController
{
    public IProductsDataSource CurrentProductsDataSource { get; set; }

    public ProductsController(IProductsDataSource productsDataSource)
    {
        CurrentProductsDataSource = productsDataSource;
    }

    [HttpGet]
    [Queryable]
    public IQueryable<ProductRestObject> Get()
    {
        return CurrentProductsDataSource.GetProducts();
    }
    protected override void Dispose(bool disposing)
    {
        CurrentProductsDataSource.Dispose();
        base.Dispose(disposing);
    }
}

I then added the following line to the RegisterTypes method in the UnityConfig class generated when I brought in the package.

container.RegisterType<IProductsDataSource, ProductsManager>();

It all worked great, but I didn’t love the fact that I would have to override the Dispose method to dispose of items that were being resolved by Unity. I knew I would have to use a LifetimeManager.

I then made the following changes:

In the Start method of my UnityWebApiActivator class, I deleted the preexisting DependencyResolver instantiation:

var resolver = new Microsoft.Practices.Unity.WebApi.
                   UnityDependencyResolver(UnityConfig.GetConfiguredContainer());

And I uncommented out the provided UnityHierarchicalDependencyResolver instantiation:

var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());

I then changed the RegisterTypes method in my UnityConfig file to the following:

container.RegisterType<IProductsDataSource, ProductsManager>(new HierarchicalLifetimeManager());

container.RegisterType<ProductsController>(
new InjectionConstructor(
        new ResolvedParameter<IProductsDataSource>()));

I was then able to remove the overridden Dispose method in the ProductsController.

And that was it.

Next Topic | Previous Topic | Home | Community