我遇到了Autofac2和MVC2的问题。问题是我正在尝试解决一系列依赖项,其中根依赖项是HttpRequestScoped。当我尝试解析我的UnitOfWork(可以是Disposable)时,Autofac会失败,因为内部处理程序正在尝试将UnitOfWork对象添加到null的内部处置列表中。也许我正在以错误的生命周期注册我的依赖项,但我尝试了许多不同的组合而没有运气。我唯一的要求是MyDataContext持续整个HttpRequest。
我发布了download here代码的演示版。
Autofac模块在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)
首先,你不应该让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
是(imo:genius!)首选使用ExternallyOwned
,因为处理外部拥有的实例不会清除注入该实例的其他依赖项。处置Owned
实例也将自动处理该实例的整个对象图。
可以找到here的一些介绍。
注意:甚至更好,现在UnitOfWork
从容器中解放出来,你可以完全抛弃IoCHelper
的东西:)
答案 1 :(得分:2)
您需要使用ContainerProvider初始化AutofacDependencyResolver,而不是RequestLifetime(只有当前请求才会生效 - 每次都会创建一个新请求。)
希望他的帮助,
尼克
答案 2 :(得分:1)
在HomeController中,您正在处理autofac将为您执行的UnitOfWork。但是,如果您希望控制何时处理对象,则需要在注册IUnitOfWork时添加ExternallyOwned。
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency().ExternallyOwned();