AutoFac has recently been updated for MVC 5.1 but at the time of writing I find that the documentation is lacking (especially for a simple example).
I would like to inject dependencies into MVC Controllers and register my own implementations for e.g. e-mail (actual sending vs print to output window) as a basic example.
I'm do not know if I am missing a good resource for this and I am slight concerned that because it uses the OWIN specification that the implementation may differ for MVC5.1 (ASP.NET Identity uses OWIN and there is some special attributes used to properly instantiate OWIN) so need to check I am getting things right.
I have a working example with the below setup code - is this correct and good practice for a standard MVC5.1 web app?
Bonus question: do I need to add InstancePerHttpRequest to the RegisterControllers line? i.e. builder.RegisterControllers(typeof(MvcApplication).Assembly).InstancePerHttpRequest();
(Note: I see the examples on GitHub from Autofac but cannot find an plain example appropriate to MVC5.1.)
public static void RegisterDependencies()
{
// Register MVC-related dependencies
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterModelBinders(typeof(MvcApplication).Assembly);
builder.RegisterModule<AutofacWebTypesModule>();
// Register e-mail service
builder.RegisterType<EmailSenderToDebug>().As<IEmailSender>().InstancePerHttpRequest();
builder.RegisterModelBinderProvider();
// Set the MVC dependency resolver to use Autofac
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
And my controller:
public class HomeController : Controller
{
public IEmailSender _email { get; set; }
public HomeController(IEmailSender es)
{
this._email = es;
}
//
// GET: /Home/
public ActionResult Index()
{
Email e = new Email();
e.To(new MailAddress("[email protected]", "mr. something"));
e.Subject("test");
e.Message("hello world");
e.From(new MailAddress("[email protected]", "mr. else"));
this._email.SendEmail(e);
return View();
}
}
Thanks!
Here's what I have - feedback welcome!
Global.asax.cs:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Register Inversion of Control dependencies
IoCConfig.RegisterDependencies();
// Typical MVC setup
// ....
}
}
App_Start folder:
public class IoCConfig
{
/// <summary>
/// For more info see
/// :https://code.google.com/p/autofac/wiki/MvcIntegration (mvc4 instructions)
/// </summary>
public static void RegisterDependencies()
{
#region Create the builder
var builder = new ContainerBuilder();
#endregion
#region Setup a common pattern
// placed here before RegisterControllers as last one wins
builder.RegisterAssemblyTypes()
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces()
.InstancePerHttpRequest();
builder.RegisterAssemblyTypes()
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerHttpRequest();
#endregion
#region Register all controllers for the assembly
// Note that ASP.NET MVC requests controllers by their concrete types,
// so registering them As<IController>() is incorrect.
// Also, if you register controllers manually and choose to specify
// lifetimes, you must register them as InstancePerDependency() or
// InstancePerHttpRequest() - ASP.NET MVC will throw an exception if
// you try to reuse a controller instance for multiple requests.
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.InstancePerHttpRequest();
#endregion
#region Register modules
builder.RegisterAssemblyModules(typeof(MvcApplication).Assembly);
#endregion
#region Model binder providers - excluded - not sure if need
//builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
//builder.RegisterModelBinderProvider();
#endregion
#region Inject HTTP Abstractions
/*
The MVC Integration includes an Autofac module that will add HTTP request
lifetime scoped registrations for the HTTP abstraction classes. The
following abstract classes are included:
-- HttpContextBase
-- HttpRequestBase
-- HttpResponseBase
-- HttpServerUtilityBase
-- HttpSessionStateBase
-- HttpApplicationStateBase
-- HttpBrowserCapabilitiesBase
-- HttpCachePolicyBase
-- VirtualPathProvider
To use these abstractions add the AutofacWebTypesModule to the container
using the standard RegisterModule method.
*/
builder.RegisterModule<AutofacWebTypesModule>();
#endregion
#region Set the MVC dependency resolver to use Autofac
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
#endregion
}
}
Then you can register modules as you see fit which is really great if you have a modularised application and you don't know what you are going to include in your project. You can nuget setup your project and no manual intervention required (I wish!)....
public class RegisterApplicationIoC : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<EmailSenderToDebug>()
.As<IEmailSender>()
.InstancePerHttpRequest();
}
}