Showing posts with label IoC. Show all posts
Showing posts with label IoC. Show all posts

Friday, January 1, 2010

Walkthrough using Autofac as your IoC Container in an ASP.NET MVC application

Note: The Autofac assemblies that I used to write this sample are part of the latest Beta version – which is a bit of a moving target.  I know that the most recent build of that major version has changed since I wrote this stuff, so you might want to keep an eye on Nick’s blog to learn about any changes that are occurring in the codebase.  One significant change you will need to know about if you are planning to work through this article is the change that he has made to how ASP.NET MVC Controllers are registered with the Container.  You can read about that change here.

If you are building properly structured software where you have correctly implemented separation of concerns (SOC) then wiring up dependencies for classes starts to become quite an exercise. Here's an example from the a great series of articles on the topic of IoC and DI that I recommend you read to learn more about the topic which shows how verbose and complex things can become:

IFileDownloader downloader = new HttpFileDownloader(); 
ITitleScraper scraper = new StringParsingTitleScraper();
HtmlTitleRetriever retriever = new HtmlTitleRetriever(downloader, scraper);


Commonly when you use simple dependency injection in this manner you find that some services are reliant upon many other components and their construction becomes very messy. You can imagine what this starts to look like when you have lots of type registration and dependency injection to do right across your application!



In this article I am going to get you up and running using Autofac as the IoC container that will handle all of the lifetime management of your dependencies and do the dependency injection for you. To get the ball rolling, go ahead and create a new solution called SimpleAutofac:



clip_image001



I like to structure my source code so that the main branch of the application lives within a folder named trunk and that my external dependencies are referenced from a folder which lives above that. Create a folder for your Autofac dependencies, grab the latest build of Autofac and add its binaries to the folder you just created.



clip_image002



You should get the following list of assemblies added to your Autofac dependencies folder



clip_image003



Next add a reference from your SimpleAutofac project in Visual Studio to the Autofac.dll, Autofac.Configuration.dll and the Autofac.Integration.Web.dll assemblies. Having done that, we can wire up Autofac into our web application and start registering types. The first thing is to take advantage of the Autofac.Integration.Web.dll which contains the AutofacControllerFactory class that can be used at the ControllerBuilder’s current ControllerFactory.



private static IContainerProvider _containerProvider;

protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);

var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule(new AutofacControllerModule(Assembly.GetExecutingAssembly()));
_containerProvider = new ContainerProvider(containerBuilder.Build());

ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(_containerProvider));
}


We need to make a minor alteration to the web.config file to include an Http Module that Autofac will use to dispose



<httpModules>
<add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
</httpModules>


The ContainerDisposal module requires us to implement the Autofac IContainerProviderAccessor interface on our Application class, which, in-turn, mandates that we expose the ContainerProvider as a property on the class. Go ahead and add the following lines of code to your Application class:



public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}

protected void Application_EndRequest(object sender, EventArgs e)
{
ContainerProvider.EndRequestLifetime();
}


You can read more about the Autofac MVC integration on the project's Wiki page. That's all there is to it, press F5 and your application should now run.



clip_image004



Note that the Controllers are now being served by our Autofac IoC container and so we can now demonstrate the advantages that we get from this by going and adding some dependencies to our Controller classes and see that they get injected at runtime for us.



Create a new interface called IMessageProvider in the Models folder of the web project.  We will use this as a dependency that we’ll then pass to controller classes:



namespace SimpleAutofac.Models
{
public interface IMessageProvider
{
string EchoMessage(string message);
}
}


And now create a concrete instance of that interface that we will use in our application. For the sake of giving meaning to the demo, let's name our class SqlMessageProvider and imagine that this class is responsible for retrieving messages from a SQL Server database. Our class will look like this:



namespace SimpleAutofac.Models
{
public class SqlMessageProvider : IMessageProvider
{
public string EchoMessage(string message)
{
return string.Format("{0} returned from message provider.", message);
}
}
}


Next we will wire up our implementation with our container so that it knows what class to return within our web application whenever an IMessageProvider is required. Go back to the Application class in Global.asax.cs and add the following registration instruction to our container builder:



containerBuilder.RegisterType<SqlMessageProvider>().As<IMessageProvider>();


Finally, go to the HomeController class and create a constructor which takes an IMessageProvider instance and then change the code in the Index action handler so that it gets its message from the IMessageProvider service as opposed to being a raw string:



namespace SimpleAutofac.Controllers
{
public class HomeController : Controller
{
private readonly IMessageProvider messageProvider;

public HomeController(IMessageProvider messageProvider)
{
this.messageProvider = messageProvider;
}

public ActionResult Index()
{
ViewData["Message"] = this.messageProvider.EchoMessage("Welcome to ASP.NET MVC!");
return View();
}

public ActionResult About()
{
return View();
}
}
}


Now press F5 to run the application and you should see that our Autofac container did indeed handle the type registration for us and it successfully injected the correct IMessageProvider instance into our HomeController class.



clip_image005



The last thing that I want to show is how to pass a connection string to our SqlMessageProvider instance whenever it is instantiated.



Go back to our SqlMessageProvider class and add a constructor that takes a connection string as an argument. Change the EchoMessage so that it shows us which connection our message came from:



private string connectionString = "";

public SqlMessageProvider(string connectionString)
{
this.connectionString = connectionString;
}

public string EchoMessage(string message)
{
return string.Format("{0} returned from {1} provider.",
message,
this.connectionString);
}



Now go back to the Application class and change the IMessageProvider registration so that it takes a specific instance that we've already pre-configured with our connection string information



var connectionString = "DarrensSqlServer";

var containerBuilder = new ContainerBuilder();
containerBuilder.Register(c => new SqlMessageProvider(connectionString)).As<IMessageProvider>();
containerBuilder.RegisterModule(new AutofacControllerModule(Assembly.GetExecutingAssembly()));

_containerProvider = new ContainerProvider(containerBuilder.Build());

ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(_containerProvider));


clip_image006