为什么 autofac 在 HttpRequest 结束之前处理对象?
我正在编写一个 ASP.NET MVC 网站,使用 autofac 进行依赖注入,并使用 Mindscape 的 Lightspeed 作为 ORM。有一个 UserRepository 类,它依赖于光速 UnitOfWork,并为 Logon 控制器提供服务。
问题:UnitOfWork 在 UserRepository 使用完毕之前就被释放了。
public class UserRepository : IUserRepository
{
private readonly BluechipModelUnitOfWork _unitOfWork;
public UserRepository(BluechipModelUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public Principal GetPrincipal(string name)
{
// This line throws an ObjectDisposedException - UnitOfWork is already disposed.
return _unitOfWork.Principals.FirstOrDefault(p => p.Name == name);
}
...
在 Global.asax 中,依赖关系连接如下完成:
public class MvcApplication : HttpApplication, IContainerProviderAccessor
{
private static void RegisterAutofac()
{
var builder = new ContainerBuilder();
// Register the lightspeed context as a singleton
builder.RegisterInstance(new LightSpeedContext<BluechipModelUnitOfWork>("LightSpeedBluechip"))
.As<LightSpeedContext<BluechipModelUnitOfWork>>()
.SingleInstance();
// Register the unit of work constructor so that a new instance is bound to each HttpRequest
builder.Register(c => c.Resolve<LightSpeedContext<BluechipModelUnitOfWork>>().CreateUnitOfWork())
.As<BluechipModelUnitOfWork>()
.InstancePerLifetimeScope();
// Register user repository to be one instance per HttpRequest lifetime
builder.Register(c => new UserRepository(c.Resolve<BluechipModelUnitOfWork>()))
.As<IUserRepository>()
.InstancePerLifetimeScope();
builder.Register(c => new CurrentUserService(
c.Resolve<HttpSessionState>(),
c.Resolve<IUserRepository>(),
c.Resolve<IMembershipService>())
).As<ICurrentUserService>()
.CacheInSession();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired().InjectActionInvoker();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
// Set the container provider up with registrations.
_containerProvider = new ContainerProvider(builder.Build());
// Set the controller factory using the container provider.
ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(_containerProvider));
鉴于上述注册,为什么 autofac 会处置 UnitOfWork (
I'm writing an ASP.NET MVC website, using autofac for dependency injection, and Mindscape's Lightspeed as the ORM. There's a UserRepository class, which depends on a lightspeed UnitOfWork, and which services the Logon controller.
Problem: The UnitOfWork gets disposed before the UserRepository is finished using it.
public class UserRepository : IUserRepository
{
private readonly BluechipModelUnitOfWork _unitOfWork;
public UserRepository(BluechipModelUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public Principal GetPrincipal(string name)
{
// This line throws an ObjectDisposedException - UnitOfWork is already disposed.
return _unitOfWork.Principals.FirstOrDefault(p => p.Name == name);
}
...
In Global.asax, the dependency wiring is done as follows:
public class MvcApplication : HttpApplication, IContainerProviderAccessor
{
private static void RegisterAutofac()
{
var builder = new ContainerBuilder();
// Register the lightspeed context as a singleton
builder.RegisterInstance(new LightSpeedContext<BluechipModelUnitOfWork>("LightSpeedBluechip"))
.As<LightSpeedContext<BluechipModelUnitOfWork>>()
.SingleInstance();
// Register the unit of work constructor so that a new instance is bound to each HttpRequest
builder.Register(c => c.Resolve<LightSpeedContext<BluechipModelUnitOfWork>>().CreateUnitOfWork())
.As<BluechipModelUnitOfWork>()
.InstancePerLifetimeScope();
// Register user repository to be one instance per HttpRequest lifetime
builder.Register(c => new UserRepository(c.Resolve<BluechipModelUnitOfWork>()))
.As<IUserRepository>()
.InstancePerLifetimeScope();
builder.Register(c => new CurrentUserService(
c.Resolve<HttpSessionState>(),
c.Resolve<IUserRepository>(),
c.Resolve<IMembershipService>())
).As<ICurrentUserService>()
.CacheInSession();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired().InjectActionInvoker();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
// Set the container provider up with registrations.
_containerProvider = new ContainerProvider(builder.Build());
// Set the controller factory using the container provider.
ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(_containerProvider));
Given the above registrations, why would autofac be disposing the UnitOfWork (
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我能够找到问题所在——这是一个愚蠢但微妙的陷阱......
我有一个 CurrentUserService 类,我注册如下:
问题是 CacheInSession(),因为 CurrentUserService 依赖于 IUserRepository,autofac 忠实地注入了该类,但随后在第一个请求结束时进行了处理。
这揭示了一些显而易见的事情,但在连接依赖项注入时需要注意一些微妙的事情:
确保高阶依赖项始终与它们所依赖的服务具有相同或更短的生命周期。就我而言,解决方案是更改上面的代码:
.... 这可以防止 CurrentUserService 超出它所依赖的实例的寿命。
I was able to track down the problem - it's a dumb but subtle gotcha...
I had a CurrentUserService class which I was registering as follows:
The problem is CacheInSession(), because the CurrentUserService depends on IUserRepository, which autofac was faithfully injecting, but then disposing of at the end of the first request.
This brings into light something obvious, yet subtle to be aware of when wiring up dependency injections:
Make sure that higher-order dependants always have the same or shorter lifetime as the services upon which they depend. In my case, the solution was to change the above code:
.... which prevents the CurrentUserService from out-living the instance upon which it depends.