IoC with Autofac and Controllers

 

Our Goal

What I’d like to do now is to use an IoC container for our MVC application. Our goal is to be able to create a concrete object: We want to instantiate the object once in code and pass it along: Instead of going through all the Controllers and manually going

image

What we have above would generally work: the downside is that

  • We need a reference to all the dependencies of the Concrete Object on compile time instead of on runtime.
  • If we want our Controllers to be fully testable and more easily extendable, we need to type the same *if null, then instantiate* on all the Controllers. This may not sound too bad, but having to do them with a million objects in a million Controllers would just be all messy. We can rid of this problem if we instantiate by code only in one area

Using Autofac

Pick up the sample in https://github.com/johnconraddomingo/Autofac.AutofacMvc

We’re using Autofac. I prefer to use it because

  • It has excellent support
  • Very easy to use compared to others
  • Many people use it which equates to a bigger community

Other folks might be put off with Autofac because of not having much control as opposed to, say, Ninject where you get to change most of the action in your project… As long as you know what you’re doing.

On the flip side, keep in mind that Autofac is Open Source, so you can pick up the source codes in modify it if it does something that you’re not happy with.

Get the Necessary References

Pick up your References from Nuget. For our sample, you’re going to need Autofac.Mvc. If you’re picking it up from within Visual Studio it will also get the main Autofac package for you

image

Integrate

Create the Interfaces and concrete objects that need to be passed around. We’ll pick up the Webserver from our Web.Config. This is just to show you that you can instantiate and do whatever you want from the startup of your application.

public interface IWebConfiguration
{
   
string WebServer { get; set; }
}

public class ConcreteObjectConfiguration : IWebConfiguration
{
  
public string WebServer { get; set; }
}

Create your Data Module. This module allows you to create your concrete objects and then register them as an implementation of your interface. What Autofac will do then is pass on the object you create here to the constructors that contains your defined interface.

This is a good idea to use for configurations and repositories.

 public class DataModule : Module
    {
       
private readonly string _webServer;
        public
DataModule(string webServer)
        {
            _webServer
= webServer;
       
}
       
protected override void Load(ContainerBuilder builder)
        {
           
// Create the Concrete Object
           
builder.Register(c => new ConcreteObjectConfiguration { WebServer = _webServer}).As<IWebConfiguration>();
            base
.Load(builder);
       
}
    }

Create a call to configure the Container. See that we pass on the WebServer value to the DataModule that we created above.

public class AutofacConfig
{
   
public static void ConfigureContainer()
    {
        var builder
= new ContainerBuilder();

        builder.RegisterControllers(typeof(MvcApplication).Assembly);
       
builder.RegisterFilterProvider();
       
builder.RegisterSource(new ViewRegistrationSource());
       
builder.RegisterModule(new DataModule(ConfigurationManager.AppSettings[“WebServer”]));
       
var container = builder.Build();

        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
   
}
}

Now, call AutofacConfig from Global.asax

protected void Application_Start()
{
   
// Call Here.
   
AutofacConfig.ConfigureContainer();

    AreaRegistration.RegisterAllAreas();
   
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
   
RouteConfig.RegisterRoutes(RouteTable.Routes);
   
BundleConfig.RegisterBundles(BundleTable.Bundles);
}

And you’re all set. From here, you can now use ConcreteObjectConfiguration on all your controllers. Notice below that we don’t even have an empty constructor. Without an IOC container, you can’t do that as it will throw you an error saying you need a parameter-less constructor

public class HomeController : Controller
{
   
public IWebConfiguration InjectedConfiguration { get; set; }
   
public HomeController(IWebConfiguration injectedConfiguration)
    {
        InjectedConfiguration
= injectedConfiguration;
   
}
        
   
public ActionResult Index()
    {
        ViewBag.Message
= $“The Webserver is in {InjectedConfiguration.WebServer}”;
        return
View();
   
}     
}

The object we created earlier will be passed to your constructor, and therefore we can do whatever we want with it. I chose to assign it to a public property so that

  • We can create a Unit Test for the Controller
  • We can use the concrete object for all of the Actions.

Here’s what it looks like now

image