My Favorite .net Open Source Projects – Autofac
The .net open source community is much more vibrant than most people realize. Many of the projects can trace their roots back to the Alt .net movement, but others are brand new. In this series, I’m going to talk about some of my favorite open source .net tools. These are tools that find themselves in most of my projects because they’re the best of the breed, at least as far as I’m concerned.
The first tool I wanted to talk about is the dependency injection tool Autofac. Autofac is what’s known as an Inversion of Control Container. Dependency injection is a way of allowing loose coupling between components inside an application by registering implementations in a container and then asking for them back through the use of an interface. There is plenty out there for the reading on inversion of control and dependency injection, and the subject of this article isn’t the idea of DI but rather how to use autofac.
To start with let’s grab either an existing project or a new one in visual studio. I’m a web guy, so my default is to start up a new web project and add autofac to it using nuget (also an open source tool, BTW):
PM> Install-Package Autofac
Installing 'Autofac 3.5.2'.
Successfully installed 'Autofac 3.5.2'.
Adding 'Autofac 3.5.2' to AutofacDemo.
Successfully added 'Autofac 3.5.2' to AutofacDemo.
With autofac included in the project, I can go about setting up a container. For MVC projects, there is also a really handy companion package that slides autofac into ASP.net’s built in dependency injection system. For you see a number of the components in MVC are already capable of being constructed from a container. This package varies by which version of MVC you’re using. In our case we’re on MVC 5.
PM> Install-Package autofac.Mvc5
Attempting to resolve dependency 'Autofac (≥ 3.4.0 && < 4.0.0)'.
Attempting to resolve dependency 'Microsoft.AspNet.Mvc (≥ 5.1.0 && < 6.0.0)'.
Attempting to resolve dependency 'Microsoft.AspNet.WebPages (≥ 3.2.2 && < 3.3.0)'.
Attempting to resolve dependency 'Microsoft.Web.Infrastructure (≥ 1.0.0.0)'.
Attempting to resolve dependency 'Microsoft.AspNet.Razor (≥ 3.2.2 && < 3.3.0)'.
Installing 'Autofac.Mvc5 3.3.4'.
Successfully installed 'Autofac.Mvc5 3.3.4'.
Adding 'Autofac.Mvc5 3.3.4' to AutofacDemo.
Successfully added 'Autofac.Mvc5 3.3.4' to AutofacDemo.
Now we have everything we need to do dependency injection in MVC. Let’s set it up. In MVC 5 the application startup is still largely done in the Global.asax.cs but we don’t want to overload that class so let’s follow the pattern that has already been laid out for us in the template: adding a class to the App_Start directory and call a static method from the Global.asax.cs.
I stole the configuration from the autofac website:
public class ContainerConfig
{
public static void BuildContainer()
{
var builder = new ContainerBuilder();
// Register your MVC controllers.
builder.RegisterControllers(typeof(MvcApplication).Assembly);
// OPTIONAL: Register model binders that require DI.
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
// OPTIONAL: Register web abstractions like HttpContextBase.
builder.RegisterModule();
// OPTIONAL: Enable property injection in view pages.
builder.RegisterSource(new ViewRegistrationSource());
// OPTIONAL: Enable property injection into action filters.
builder.RegisterFilterProvider();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
To this code we add any services or other components we'd like to use. Let's try that by adding a service to our application and getting it from the container. The first step is to write a contract or interface which describes the service. In our case we want a service which resolves a given name into a new one using the childhood game of "banana nana bo banna". For our implementation of this rhyming game we simply manipulate the string a little. So the contract needs only to take in a string, the name, and return another string, the rhyme. Thus the contract looks like
namespace AutofacDemo.Services
{
public interface INameResolver
{
string GetName(string inputName);
}
}
and our naïve implementation looks like
namespace AutofacDemo.Services
{
public class NameResolver : INameResolver
{
public string GetName(string inputName)
{
return string.Format("{0} {0} bo bolly fee fi fo folly {0}", inputName);
}
}
}
With the service in place we would like to register it in the container so to the ContainerConfig we add
// Add our own components
builder.RegisterType().As();
Here we explicitly registered the type and the interface. In most scenarios you'll want to make use of namespace based registration so something like
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(x=>x.Name.EndsWith("Service"))
.AsImplementedInterfaces();
This code will search the currently executing assembly for anything that ends with the word "Service" and registers it as the implemented interfaces. You can see the ease of using the fluent registration API in Autofac. The final step is to inject this service into one of our controllers. We'll use the Home controller and the action "About". We start by adding a new constructor that takes in the service and assigns it to a private variable.
private readonly INameResolver _nameResolver;
public HomeController(INameResolver nameResolver)
{
_nameResolver = nameResolver;
}
Autofac does support property injection too where it will set public properties on the built up class. I tend to avoid public property injection as I believe it opens up too much data to outside observers. I've flip-flopped on this for years, though, so I might feel differently next week. With the service in place all that is left is for us to actually use it
public ActionResult About()
{
ViewBag.Message = _nameResolver.GetName("Ollie");
return View();
}
The Home > About page now shows us
It is just that easy to get started with Autofac and dependency injection. All the code from this post is available on github at https://github.com/stimms/AutofacDemo