Problem with Autofac 2 and MVC2 using HttpRequestScoped

I have a problem with Autofac2 and MVC2. The problem is that I am trying to resolve a number of dependencies, where the root dependency is HttpRequestScoped. When I try to resolve my UnitOfWork (which is one-time), Autofac fails because the internal removal device is trying to add the UnitOfWork object to the internal removal list, which is null. Maybe I am registering my addictions with the wrong lifespan, but I have tried many different combinations with no luck. The only requirement I have is that MyDataContext lasts for the entire HttpRequest.

I posted a demo of the code to download here .

Autofac modules are configured 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();
    }
}
0
3

HomeController UnitOfWork, autofac . , , , ExternallyOwned IUnitOfWork.

builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency().ExternallyOwned();
+1

-, , UnitOfWork . BeginWork HomeController:

public class HomeController : Controller
{
    private readonly IMyService _myService;
    private readonly Func<Owned<IUnitOfWork>> _unitOfWorkFactory;

    public HomeController(IMyService myService, Func<Owned<IUnitOfWork>> unitOfWorkFactory)
    {
        _myService = myService;
        _unitOfWorkFactory = unitOfWorkFactory;
    }

    public ActionResult Index()
    {
        using(var unitOfWork = _unitOfWorkFactory())
        {
            _myService.Add();

            unitOfWork.Value.Commit();
        }

        return View();
    }

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

Func<> factory Autofac2 , . , Owned<IUnitOfWork>, ,

, , .

Owned , , , .

Owned - (imo: genius!), , ExternallyOwned, , , , . Owned .

.

: , , UnitOfWork , IoCHelper:)

+3

You need to initialize AutofacDependencyResolver using ContainerProvider, not RequestLifetime (which lives only as long as the current request - a new one is created each time.)

Hope this helps,

Nick

+2
source

All Articles