0

我遇到了 Autofac2 和 MVC2 的问题。问题是我正在尝试解决根依赖项是 HttpRequestScoped 的一系列依赖项。当我尝试解析我的 UnitOfWork(可处置)时,Autofac 失败,因为内部处置器试图将 UnitOfWork 对象添加到为空的内部处置列表中。也许我正在使用错误的生命周期注册我的依赖项,但我尝试了许多不同的组合但没有运气。我唯一的要求是 MyDataContext 持续整个 HttpRequest。

我已在此处发布了代码的演示版本以供下载

Autofac 模块在 web.config 中设置

全球.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");
    }
}

我的服务.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.
   }
}

家庭控制器.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();
    }
}
4

3 回答 3

3

首先,你不应该让 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<>Autofac2 中自动可用,并将为您提供创建指定类型实例的委托。接下来,因为我们要求Owned<IUnitOfWork>我们得到一个实例

在底层,一个 Owned 被分配了它自己的嵌套生命周期范围,因此它的所有依赖项都会在它被清理时被清理。

Owned实例表明您作为依赖消费者负责处置该实例。

Owned是(imo:天才!)首选以上使用,ExternallyOwned因为处理外部拥有的实例不会清理注入该实例的其他依赖项。处置一个Owned实例也将自动处置该实例的整个对象图。

可以在此处找到对此的一些介绍。

注意:更好的是,现在它UnitOfWork从容器中释放出来了,你可以完全扔掉它IoCHelper:)

于 2010-04-29T08:06:28.533 回答
2

您需要使用 ContainerProvider 初始化 AutofacDependencyResolver,而不是 RequestLifetime (它只存在于当前请求的时间 - 每次都会创建一个新请求。)

希望他的帮助,

缺口

于 2010-04-29T08:04:54.073 回答
1

在 HomeController 中,您正在处理 Autofac 将为您执行的 UnitOfWork。但是,如果您希望控制何时处理对象,则需要将 ExternallyOwned 添加到您的 IUnitOfWork 注册中。

builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency().ExternallyOwned();
于 2010-04-28T17:13:22.740 回答