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

IoC in ASP.NET MVC using Autofac

0.00/5 (No votes)
18 Aug 2014 1  
Using Autofac IoC container in MVC application to resolve dependencies. Scenarios included: controller, custom filter and view dependency injection

Introduction

In this article I will demonstrate how you can use Autofac IoC container in MVC application. This article will cover various dependency injection scenarios in MVC, namely: controller, custom filter and view dependency injection. 

Solution setup

In large applications development you will usually have different projects which contains different parts of your architecture like data, services, UI ..etc. Thats why in this article I have created a solution that contains more than one project so it can be as close to real application development as possible. Figure 1 shows the solution structure.

Figure 1: Solution Setup

MVCWithAutofac.Core contains the model and the various interfaces used in MVCWithAutofac.Data (Data) project. The Data project contains EF code first context and implementation for the repository interfaces defined in MVCWithAutofac.Core. The implementation details for these two projects are explained in details in my article entitled: Repository with Unit of Work, IoC and Unit Test. I will point out any new files/implementation in these two projects which are added in this article.

The focus of this article will be on the implementation of MVCWithAutofac.Web. Thats where our Autofac IoC is put into practice to implement the various dependency injection (DI) scenarios you may want to use in your MVC application.

Using Autofac Module

It is advisable to structure the building for the IoC container so that it is easy to maintain. One way to do that is to use Autofac Module. Autofac Module allows you to delegate the building of different parts of your IoC to each project that has dependencies which you may want to use. This way you don’t have to cram 10’s of dependencies in one place which makes it harder to maintain on the long run.


I have make use of this feature in DataModule. DataModule is responsible for registering the dependencies which are defined in the data project and which will be used in MVCWithAutofac.Web. Listing 1 shows the implementation for DataModule

using Autofac;
using MVCWithAutofac.Core.Interfaces;
 
namespace MVCWithAutofac.Data
{
    public class DataModule : Module
    {
        private string connStr;
        public DataModule(string connString)
        {
            this.connStr = connString;
        }
        protected override void Load(ContainerBuilder builder)
        {
            builder.Register(c => new EFContext(this.connStr)).
                             As<IDbContext>().InstancePerRequest();

            builder.RegisterType<SqlRepository>().As<IRepository>().InstancePerRequest();
            builder.RegisterType<TeamRepository>().As<ITeamRepository>().InstancePerRequest();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();         
 
            base.Load(builder);
        }
    }
}

Listing 1: DataModule implementation

The class inherits from Module and overrides the load method. The Load method takes an instance of ContainerBuilder.

Note that the constructor is accepting a connection string name. This is used to create the EF context. This is very handy because you can pass your connection string from where you will be building your IoC container (as we will see later). In our case this will be the web project. The usefulness of passing the connection string name is that you can use various connection strings depending on the environment you are in. Also you are removing the responsibility of getting the connection string from the Data project.

The Load method uses the ContainerBuilder to register the various Data dependencies like the EF context and the repositories.

Building the IoC container

The ideal place to hook the building for our Autofac IoC container is in the Application_Start method in Global.asax file. Listing 2 shows the implementation of Application_Start method.

protected void Application_Start()
{
    AutofacConfig.ConfigureContainer();
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

Listing 2: Application_Start implementation

The implementation of this method is very familiar to MVC developers apart from this line: AutofacConfig.ConfigureContainer(). This is were our IoC will be built. Listing 3 shows the implementation of AutofacConfig class.

using Autofac;
using Autofac.Integration.Mvc;
using System.Web.Mvc;
using MVCWithAutofac.Data;
 
namespace MVCWithAutofac.Web
{
    public class AutofacConfig
    {
        public static void ConfigureContainer()
        {
            var builder = new ContainerBuilder();
            
            // Register dependencies in controllers
            builder.RegisterControllers(typeof(MvcApplication).Assembly);
 
            // Register dependencies in filter attributes
            builder.RegisterFilterProvider();
 
            // Register dependencies in custom views
            builder.RegisterSource(new ViewRegistrationSource());
 
            // Register our Data dependencies
            builder.RegisterModule(new DataModule("MVCWithAutofacDB"));
            
            var container = builder.Build();
 
            // Set MVC DI resolver to use our Autofac container
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }
    }
}

Listing 3: AutofacConfig implementation

Notice the using statement. We are using Autofac as well as Autofac.Integration.Mvc. The latter is a seperate package which you need to download separately from nuget package manager.

As the name implied Autofac.Integration.Mvc contains the logic required to integrate the Autofac container in MVC application. The implementation of RegisterControllers, RegisterFilterProvider and ViewRegistrationSource lives in Autofac.Integration.Mvc.

Controller DI

I am using Autofac to resolve the dependencies in TeamController. Listing 4 shows part of TeamController’s implementation.

public class TeamController : Controller
{
    private IRepository repo;
    public TeamController(IRepository repo)
    {
        this.repo = repo;
    }
 
    [HttpGet]
    public ActionResult Index()
    {
        var teams = repo.GetAll<Team>().ToList();
        return View(teams);
    }
}

Listing 4: DI in TeamController

This type of injection is called constructor injection. I am resolving the IRepository implementation at runtime. The Index action is making use of the repo field to retrieve the teams.

Note that I am using the IRepository interface rather than the concrete implementation. This is useful in unit testing. It is also useful to switch implementations or use more than one implementation for the same interface and resolve a specific one depending on the context.

Filter attribute DI

I have created a custom action filter attribute to demeonestrate DI in filters attributes. The LogActionFilter is a filter attribute that can be applied to actions. Listing 5 shows the implementation of LogActionFilter

using MVCWithAutofac.Core.Interfaces;
using MVCWithAutofac.Core.Model;
using System.Web.Mvc;
 
namespace MVCWithAutofac.Web.Filters
{
    public class LogActionFilter : ActionFilterAttribute
    {
        public IRepository repo { set; get; }
 
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            repo.Insert<Log>(new Log
            {
                Action = string.Format("Controller: {0} , Action: {1}",
                    filterContext.ActionDescriptor.ActionName,
                    filterContext.ActionDescriptor.ControllerDescriptor.ControllerName),
                Name = "Log entry"
            });
            repo.SaveChanges();
        }
    }
}

Listing 5: LogActionFilter implementation

LogActionFilter inherits from ActionFilterAttrinute and ovverrides the OnActionExecuted Method. Note how the repository dependency is being resolved using a property. This is called property injection.

The implementation of OnActionExecuted is using the repository to create a log entry in the Log table. The log entry details the action and the controller name. The Log entity is defined in the Data project. Listing 6 shows the log entity.

namespace MVCWithAutofac.Core.Model
{
    public class Log : BaseModel<int>
    {
        public string Action { get; set; }
    }
}

Listing 6: Log entity

I am using this filter attribute on the insert team action as showing in listing 7. After this action is executed our action filter will kick in to add an entry to the log table.

[HttpPost]
[LogActionFilter]
public ActionResult InsertTeam(Team team)
{
    if (ModelState.IsValid)
    {
        repo.Insert<Team>(team);
        repo.SaveChanges();
        return RedirectToAction("Index");
    }
    
    return View();
}

Listing 7: Applying LogActionFilter attribute

Custom View DI

Razor view engine allows you to use custom base view for your views within MVC application. The reason why you want to do this varies depending on your needs. This is a good article that shows how and why you want to do that. Our focus here though is how can you have DI in your custom view base class.


CustomBasePage inherits from WebViewPage and defines two properties namely: teamRepo and repo. These two properties will be resolved from our Autofac IoC container at runtime. Listing 8 shows the implementation for CustomBasePage

using MVCWithAutofac.Core.Interfaces;
using System.Web.Mvc;
 
namespace MVCWithAutofac.Web.BasePages
{
    public class CustomBasePage : WebViewPage
    {
        public ITeamRepository teamRepo { get; set; }
        public IRepository repo { get; set; }
        
        public override void Execute() { }        
    }
}

Listing 8: CustomBasePage implementation

I am using this custom base view in my TeamDetails.cshtml view to show the team members in a given team. Listing 9 shows the implementaiton of TeamDetails.cshtml

@inherits MVCWithAutofac.Web.BasePages.CustomBasePage
@{
    ViewBag.Title = "Team Details";
    var team = repo.GetById<MVCWithAutofac.Core.Model.Team>(ViewBag.TeamId);
}
 
<h2>Team Details: @team.Name</h2>
<ul>
    @foreach (var teamMember in teamRepo.GetUsersInTeam(team.Id))
    {
        <li style="margin-left: 20px;">@teamMember.Name</li>
    }
</ul>

Listing 9: TeamDetails.cshtml implementaiton

Note how this view inherits from our CustomBasePage using the @inherits Razor syntax. This view gets the team with the id that is been passed through ViewBag collection then making use of teamRepo property on CustomBasePage to get the team members of that team. The action for this view is shown in listing 10

public ActionResult TeamDetails(int id)
{
    ViewBag.TeamId = id;
    return View();
}

Listing 10: TeamDetails action

As you can see that this action is only getting the teamId and store it in the ViewBag collection then returning the View (TeamDetails).

For completness here is the implementation for the generic method GetById which is new to the Data project

public TEntity GetById<TEntity>(int id) where TEntity : BaseModel<int>
{
    return (from item in GetAll<TEntity>()
            where item.Id == id
            select item).SingleOrDefault();
}

Listing 11: GetById method

Note on the side

The motivation behind this article was to explain how you can implement DI in MVC application including controller, filter attribute and custom views. As such not all best practices were followed as this was not the purpose of this article.

For example the log filter attribute should have a logger dependency without specifying were that logger will log the information. The logger inturn may use an EF context dependency or call a service to log the action. Another example is calling the repository from the view in TeamDetails.cshtml. Clearly this is not something you want to do in your production code but the idea was to explain how can you use DI in custom views.

Conclusion

In this article I have explained how can you utilize Autofac to create an IoC container for your MVC application. The scenarios where DI was applied were controller, filter attribute and custom views. I have explained how you can build your IoC container in the Application_Start method and how you can reduce the overhead of creating IoC container by utilizing the Module class from Autofac. 

 

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