代码之家  ›  专栏  ›  技术社区  ›  Page

使用httprequestscoped的autofac 2和mvc2出现问题

  •  0
  • Page  · 技术社区  · 16 年前

    我遇到了autofac2和mvc2的问题。问题是,我试图解决一系列依赖项,其中根依赖项是httprequestscope。当我试图解析我的unitofwork(它是可丢弃的)时,autofac失败,因为内部处理程序正试图将unitofwork对象添加到一个为空的内部处理列表中。也许我把我的依赖项注册到了错误的生命周期,但我尝试了许多不同的组合,但都没有成功。我唯一的要求是mydatacontext持续到整个httprequest。

    我已经发布了 download here .

    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>();
        }
    }
    

    小精灵

    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>();
        }
    }
    

    工作单元.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

    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();
        }
    }
    
    3 回复  |  直到 16 年前
        1
  •  1
  •   Thad    16 年前

    在Homecontroller中,您正在处理AutoFac将为您执行的UnitOfWork。但是,如果您希望控制何时释放对象,则需要将externallyowned添加到iunitofwork的注册中。

    builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency().ExternallyOwned();
    
        2
  •  3
  •   Peter Lillevold Rene    16 年前

    首先,不应该让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 实例指示您作为依赖项使用者负责释放实例。

    拥有 IS(国际海事组织:天才!)优于使用 ExternallyOwned 因为处理外部拥有的实例不会清除注入该实例的其他依赖项。处置一 拥有 实例还将自动释放该实例的整个对象图。

    这方面的一些介绍可以找到 here .

    注: 更好,现在 UnitOfWork 是免费的,你可以把 IoCHelper 总而言之:)

        3
  •  2
  •   Nicholas Blumhardt    16 年前

    您需要使用ContainerProvider初始化AutoFacDependencyResolver,而不是使用requestLifetime(它只与当前请求存在一段时间—每次都会创建一个新请求)。

    希望他的帮助,

    尼克