Issue with Autofac 2 and MVC2 using HttpRequestScoped
- by Page Brooks
I'm running into an issue with Autofac2 and MVC2. The problem is that I am trying to resolve a series of dependencies where the root dependency is HttpRequestScoped. When I try to resolve my UnitOfWork (which is Disposable), Autofac fails because the internal disposer is trying to add the UnitOfWork object to an internal disposal list which is null. Maybe I'm registering my dependencies with the wrong lifetimes, but I've tried many different combinations with no luck. The only requirement I have is that MyDataContext lasts for the entire HttpRequest.
I've posted a demo version of the code for download here.
Autofac modules are set up in web.config
Global.asax.cs
protected void Application_Start()
{
string connectionString = "something";
var builder = new ContainerBuilder();
builder.Register(c => new MyDataContext(connectionString)).As<IDatabase>().HttpRequestScoped();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency();
builder.RegisterType<MyService>().As<IMyService>().InstancePerDependency();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
_containerProvider = new ContainerProvider(builder.Build());
IoCHelper.InitializeWith(new AutofacDependencyResolver(_containerProvider.RequestLifetime));
ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(ContainerProvider));
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
AutofacDependencyResolver.cs
public class AutofacDependencyResolver
{
private readonly ILifetimeScope _scope;
public AutofacDependencyResolver(ILifetimeScope scope)
{
_scope = scope;
}
public T Resolve<T>()
{
return _scope.Resolve<T>();
}
}
IoCHelper.cs
public static class IoCHelper
{
private static AutofacDependencyResolver _resolver;
public static void InitializeWith(AutofacDependencyResolver resolver)
{
_resolver = resolver;
}
public static T Resolve<T>()
{
return _resolver.Resolve<T>();
}
}
UnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
void Commit();
}
public class UnitOfWork : IUnitOfWork
{
private readonly IDatabase _database;
public UnitOfWork(IDatabase database)
{
_database = database;
}
public static IUnitOfWork Begin()
{
return IoCHelper.Resolve<IUnitOfWork>();
}
public void Commit()
{
System.Diagnostics.Debug.WriteLine("Commiting");
_database.SubmitChanges();
}
public void Dispose()
{
System.Diagnostics.Debug.WriteLine("Disposing");
}
}
MyDataContext.cs
public interface IDatabase
{
void SubmitChanges();
}
public class MyDataContext : IDatabase
{
private readonly string _connectionString;
public MyDataContext(string connectionString)
{
_connectionString = connectionString;
}
public void SubmitChanges()
{
System.Diagnostics.Debug.WriteLine("Submiting Changes");
}
}
MyService.cs
public interface IMyService
{
void Add();
}
public class MyService : IMyService
{
private readonly IDatabase _database;
public MyService(IDatabase database)
{
_database = database;
}
public void Add()
{
// Use _database.
}
}
HomeController.cs
public class HomeController : Controller
{
private readonly IMyService _myService;
public HomeController(IMyService myService)
{
_myService = myService;
}
public ActionResult Index()
{
// NullReferenceException is thrown when trying to
// resolve UnitOfWork here.
// Doesn't always happen on the first attempt.
using(var unitOfWork = UnitOfWork.Begin())
{
_myService.Add();
unitOfWork.Commit();
}
return View();
}
public ActionResult About()
{
return View();
}
}