C# 通过依赖项注入使用异步控制器时dbContext的生存期
在过去,我使用AutoFac将EntityFramework DB上下文注入到InstancePerRequest时间表上的各种服务中C# 通过依赖项注入使用异步控制器时dbContext的生存期,c#,asp.net-mvc-4,asynchronous,dependency-injection,autofac,C#,Asp.net Mvc 4,Asynchronous,Dependency Injection,Autofac,在过去,我使用AutoFac将EntityFramework DB上下文注入到InstancePerRequest时间表上的各种服务中 builder.RegisterType<MyDataContext>() .As<IDataContext>() .As<IUnitOfWork>() .InstancePerRequest(); 我有一个动作过滤器,它在每个动作请求结束时提交我的上下文(我可能正在考虑更改它,但
builder.RegisterType<MyDataContext>()
.As<IDataContext>()
.As<IUnitOfWork>()
.InstancePerRequest();
我有一个动作过滤器,它在每个动作请求结束时提交我的上下文(我可能正在考虑更改它,但现在它符合我这个问题的目的)
我在MVC中对async的理解是,启动请求的线程不能保证完成请求,因为在使用wait
时它被释放了
在AutoFac注入中,这是否意味着注入到ActionFilterAttribute的UnitOfWork实例可能与注入到控制器的实例不同,或者InstancePerRequest不受处理请求的线程更改的影响?
InstancePerRequest
将不受影响受处理请求的线程更改的影响,因为它不会在线程内部存储任何内容。如果您阅读InstancePerRequest()
方法的源代码,您将看到它只是使用一个众所周知的scope标记调用InstancePerMatchingLifetimeScope
另一方面,在AutoFac.Mvc
项目中,您将看到在RequestLifetimeScopeProvider
类中,它将范围存储在HttpContext中,而HttpContext不受执行线程中更改的影响
剩下的唯一问题是:您的筛选器是否在启动请求范围的AutoFac筛选器的范围内执行?好的,最可靠的方法是确保您的UnitOfWork
被注入到您的过滤器中。假设是这样,您可以确信它与整个请求其余部分中存在的UnitOfWork
是相同的
我同意其他人的建议,不要在这样的筛选器中提交您的UnitOfWork
(DbContext
)。一组你已经读过的理由。另一个原因是(对我来说)它意味着您选择的模式永远不会从您的单个服务方法内部调用SaveChanges()
,而是等到最后以原子方式提交所有内容。这将一直正常工作,直到它不正常为止,例如当EF更新或以错误的顺序插入实体时。在这一点上,你已经把自己画进了一个角落
我可能还认为这样做是为了避免显式使用事务带来的麻烦,因为如果只调用一次SaveChanges()
,所有更新都将在SaveChanges()
内部的单个独立事务中发生,因此可以避免这种痛苦。这种在EF中从不使用显式事务的想法也是一个陷阱,一旦你的应用程序变得非常复杂,尽管在网络上的各种文章中都“流行”了。我建议您规划您的基础设施以适应它。谢天谢地,如果您使用的是AutoFac之类的工具,那么您可以相当透明地将事务附加到请求范围(全有或全无方法),或者在运行时创建一个包含事务的新范围,例如当您有选择地需要事务时
一种可能的解决方案是在不使用周围事务的情况下调用只读服务调用(以避免任何DB锁定),并且只在知道要写入数据库时使用事务。在每个操作请求结束时提交上下文实际上可能是一个非常糟糕的主意,因为“在应用程序的这一点上,您根本无法确定是否应该提交工作单元”。请查看以了解更多信息。@steven是的,谢谢,我想我在调查期间确实读到了这个问题。我理解这是错误的/不可取的,并会改变它,但我的实际问题仍然存在。
// Note each of these services take a IDataContext via constructor injection
public FilesController(
IAnalysisService analysisService,
IUserService userService)
{
}
public class UnitOfWorkActionAttribute : ActionFilterAttribute
{
public IUnitOfWork UnitOfWork { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
UnitOfWork.SaveChangesAsync().WaitAndUnwrapException();
}
}