Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET MVC with Unity (Dependency Injection)

0.00/5 (No votes)
18 Jun 2014 2  
How to use the Unity container to add support for dependency injection to a real-world application

Introduction

How to use the Unity container to add support for dependency injection to a real-world application and how you can use a Unity container to register types, resolve types at runtime, and manage the lifetime of the resolved objects. In addition to seeing how the Unity container made it possible to build the application’s object graph at startup, you also saw how this approach facilitated designing and running unit tests.

Background

I quoted information about Unity from article: http://unity.codeplex.com

The Unity Application Block (Unity) is a lightweight extensible dependency injection container with support for constructor, property, and method call injection.

Unity addresses the issues faced by developers engaged in component-based software engineering. Modern business applications consist of custom business objects and components that perform specific or generic tasks within the application, in addition to components that individually address cross cutting concerns such as logging, authentication, authorization, caching, and exception handling.

The key to successfully building such applications is to achieve a decoupled or very loosely coupled design. Loosely coupled applications are more flexible and easier to maintain. They are also easier to test during development. You can mock up shims (lightweight mock implementations) of objects that have strong concrete dependencies; such as database connections, network connections, ERP connections, and rich user interface components.

Dependency injection is a prime technique for building loosely coupled applications. It provides ways to handle the dependencies between objects. For example, an object that processes customer information may depend on other objects that access the data store, validate the information, and check that the user is authorized to perform updates. Dependency injection techniques can ensure that the customer class correctly instantiates and populates all of these objects, especially where the dependencies may be abstract.

Using Code (EF with CODE FIRST)

0. Preparing

Create an ASP.NET MVC with existing template in Visual Studio 2012 or 2013.

Install package:

1. Create a Table in Database

First, we create a table with name being Articles in the database as below:

CREATE TABLE [dbo].[Articles]
(
    [Id] [uniqueidentifier] NOT NULL,
    [Title] [nvarchar](100) NOT NULL,
    [Summary] [nvarchar](500) NULL,
    [ArticleContent] [nvarchar](max) NULL,
    [ViewCount] [int] NULL,
    [CreatedDate] [datetime] NULL,
    [CreatedByUsername] [varchar](50) NULL,
    [Tags] [nvarchar](500) NULL,
    CONSTRAINT [PK_Articles] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )
)

2. Create a Class Article in Folder Models of an ASP.NET MVC Project

Second, we create a class with name as Article (in folder Models of an ASP.NET MVC project) corresponding table Articles in database as below:
using System;

namespace UnityTutorials.Models
{
    public class Article
    {
        public Guid Id { get; set; }
        public string Title { get; set; }
        public string Summary { get; set; }
        public string ArticleContent { get; set; }
        public int ViewCount { get; set; }
        public DateTime CreatedDate { get; set; }
        public string CreatedByUsername { get; set; }
        public string Tags { get; set; }
    }
}

3. Create a Class ArticleMapping in Folder Models of an ASP.NET MVC Project

Third, we create a class with name ArticleMapping (in folder Models of an ASP.NET MVC project) as below:

using System.Data.Entity.ModelConfiguration;

namespace UnityTutorials.Models
{
    public class ArticleMapping : EntityTypeConfiguration<Article>
    {
        public ArticleMapping()
        {
            this.HasKey(x => x.Id);
            this.ToTable("Articles"); // map to Articles table in database
        }
    }
}

4. Create an Interface IWebDbContext and a Class WebDbContext Implement IWebDbContext Interface in Folder Models of an ASP.NET MVC Project

using System;
using System.Data.Entity;

namespace UnityTutorials.Models
{
    public interface IWebDbContext : IDisposable
    {

    }

    public class WebDbContext : DbContext, IWebDbContext
    {
        public DbSet<Article> Articles { get; set; }

        public WebDbContext()
        {
            Configuration.LazyLoadingEnabled = true;
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            // Mappings
            modelBuilder.Configurations.Add(new ArticleMapping());

            base.OnModelCreating(modelBuilder);

        }

        public new void Dispose()
        {

        }
    }
}

5. Create a Class ArticleRepository in Folder Models of an ASP.NET MVC Project

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace UnityTutorials.Models
{
    public interface IArticleRepository
    {
        IEnumerable<Article> GetAll();
        Article Add(Article item);
        void Update(Article item);
        void Delete(Article item);
        Article Get(Guid id);
    }

    public class ArticleRepository : IArticleRepository
    {
        private readonly WebDbContext _context;

        public ArticleRepository(IWebDbContext context)
        {
            this._context = context as WebDbContext;
        }

        public Article Get(Guid id)
        {
            return _context.Articles.FirstOrDefault(x => x.Id == id);
        }
        public IEnumerable<Article> GetAll()
        {
            return _context.Articles;
        }

        public Article Add(Article item)
        {
            this._context.Articles.Add(item);
            return item;
        }

        public void Update(Article item)
        {
            // Check there's not an object with same identifier already in context
            if (_context.Articles.Local.Select(x => x.Id == item.Id).Any())
            {
                throw new ApplicationException("Object already exists in context");
            }
            _context.Entry(item).State = EntityState.Modified;
        }

        public void Delete(Article item)
        {
            this._context.Articles.Remove(item);
        }
    }
}

6. Create a Class UnitOfWork to Manage Transaction

With the Entity Framework, most of the time SaveChanges() is sufficient. This creates a transaction, or enlists in any ambient transaction, and does all the necessary work in that transaction.

using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

namespace UnityTutorials.Models
{
    public partial interface IUnitOfWork : IDisposable
    {
        void Commit();
    }
    public class UnitOfWork : IUnitOfWork
    {
        private readonly WebDbContext _context;
        private readonly IDbTransaction _transaction;
        private readonly ObjectContext _objectContext;

        public UnitOfWork(IWebDbContext context)
        {
            this._context = context as WebDbContext ?? new WebDbContext();

            this._objectContext = ((IObjectContextAdapter)this._context).ObjectContext;

            if (this._objectContext.Connection.State != ConnectionState.Open)
            {
                this._objectContext.Connection.Open();
                this._transaction = _objectContext.Connection.BeginTransaction();
            }
        }

        public void Commit()
        {
            try
            {
                this._context.SaveChanges();
                this._transaction.Commit();
            }
            catch (Exception)
            {
                Rollback();
                throw;
            }
        }

        private void Rollback()
        {
            this._transaction.Rollback();

            foreach (var entry in this._context.ChangeTracker.Entries())
            {
                switch (entry.State)
                {
                    case EntityState.Modified:
                        entry.State = EntityState.Unchanged;
                        break;
                    case EntityState.Added:
                        entry.State = EntityState.Detached;
                        break;
                    case EntityState.Deleted:
                        entry.State = EntityState.Unchanged;
                        break;
                }
            }
        }

        public void Dispose()
        {
            if (this._objectContext.Connection.State == ConnectionState.Open)
            {
                this._objectContext.Connection.Close();
            }
        }
    }
}

7. Create a Class UnitOfWorkManage to Manage UnitOfWork

using System;
using System.Data.Entity;

namespace UnityTutorials.Models
{
    public interface IUnitOfWorkManager : IDisposable
    {
        IUnitOfWork NewUnitOfWork();
    }

    public class UnitOfWorkManager : IUnitOfWorkManager
    {
        private bool _isDisposed;
        private readonly WebDbContext _context;

        public UnitOfWorkManager(IWebDbContext context)
        {
            Database.SetInitializer<WebDbContext>(null);
            this._context = context as WebDbContext;
        }

        public IUnitOfWork NewUnitOfWork()
        {
            return new UnitOfWork(this._context);
        }

        public void Dispose()
        {
            if (this._isDisposed == false)
            {
                this._context.Dispose();
                this._isDisposed = true;
            }
        }
    }
}

8. Now, Test Our Unity

Step 1: Create a class called as BaseController

using System.Web.Mvc;
using UnityTutorials.Models;

namespace UnityTutorials.Controllers
{
    public class BaseController : Controller
    {
        protected readonly IUnitOfWorkManager UnitOfWorkManager;
        // GET: Base

        public BaseController(IUnitOfWorkManager unitOfWorkManager)
        {
            UnitOfWorkManager = unitOfWorkManager;
        }
    }
}

Step 2: Create a class called as ArticleController

using System;
using System.Web.Mvc;
using UnityTutorials.Models;

namespace UnityTutorials.Controllers
{
    public class ArticleController : BaseController
    {
        private readonly IArticleRepository _articleRepository;

        public ArticleController(IUnitOfWorkManager unitOfWorkManager, IArticleRepository articleRepository)
            : base(unitOfWorkManager)
        {
            this._articleRepository = articleRepository;
        }

        public ActionResult Test()
        {
            // Create a article
            using (var unitOfWork = this.UnitOfWorkManager.NewUnitOfWork())
            {
                this._articleRepository.Add(new Article()
                {
                    Id = Guid.NewGuid(),
                    Title = "Title Text",
                    Summary = "Summary Text",
                    ArticleContent = "Html content",
                    ViewCount = 0,
                    CreatedDate = DateTime.Now,
                    CreatedByUsername = "admin",
                    Tags = "mvc, unity, asp.net"
                });

                unitOfWork.Commit();
            }

            return View();
        }
    }
}

9. Create Class Called as UnityMvc5 to Register Unity with ASP.NET MVC

Notes: Remember install Unity.Mvc5, using Nuget in Visual Studio to install: Install-Package Unity.Mvc5

You can reference: https://www.nuget.org/packages/Unity.Mvc5/

using System.Web.Mvc;
using Microsoft.Practices.Unity;
using Unity.Mvc5;

namespace UnityTutorials.Models
{
    public static class IocExtensions
    {
        public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
        {
            container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
        }

        public static void BindInSingletonScope<T1, T2>(this IUnityContainer container) where T2 : T1
        {
            container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
        }
    }
    public class UnityMvc5
    {
        public static void Start()
        {
            var container = BuildUnityContainer();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }

        private static IUnityContainer BuildUnityContainer()
        {
            var container = new UnityContainer();

            // register all your components with the container here
            // it is NOT necessary to register your controllers

            // Database context, one per request, ensure it is disposed
            container.BindInRequestScope<IWebDbContext, WebDbContext>();

            //Bind the various domain model services and repositories that e.g. our controllers require         
            container.BindInRequestScope<IUnitOfWorkManager, UnitOfWorkManager>();
            container.BindInRequestScope<IArticleRepository, ArticleRepository>();

            //container.BindInRequestScope<ISessionHelper, SessionHelper>();

            return container;
        }
    }
}

10. Start Unity at Application_Start Event in Global.asax

Add line: UnityMvc5.Start();

using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace UnityTutorials
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            UnityMvc5.Start(); // <----- Add this line                          

            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}

Reference

The main references are given below:

Summary

I have put my time and efforts in all of my articles. Please don't forget to mark your votes, suggestions and feedback to improve the quality of this and upcoming articles. Thanks for reading.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here