也许这个问题有一些解释,但找不到最佳解决方案:
我正在阅读Mark Seemann的blog post关于俘获依赖性的信息,据我了解,在文章结尾处,他得出的结论是从不使用或至少尝试避免俘获依赖性,否则将会出现麻烦(到目前为止,还可以)。这是Autofac文档中的另一个post。
他们建议仅通过 目的 (知道您在做什么!)来使用俘虏依赖项。这使我想到了我网站上的情况。我有10种服务,它们全部依靠DbContext
进行数据库操作。我认为,如果我解决了InstancePerLifetimeScope
的问题,而不是将其永久保存在附加到我的服务的内存中,则可以轻松将它们注册为DbContext
。 (我正在使用Autofac)。因此,我认为一个好的出发点是根据生命周期实例创建所有这些,并根据请求创建DbContext
作为实例。然后在我的服务中,我会使用类似的东西:
public class MyService
{
private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();
private MyModel GetMyModel() => Mapper.Map<MyModel>(_dbContext.MyTable.FirstOrDefault());
}
然后在我的启动课程中,我有:
builder.RegisterType<ApplicationDbContext>().As<IDbContext>().InstancePerRequest();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
此模式是否正常工作,我的意思是不要将dbContext
永远附加在任何服务上,因此它将在请求的末尾处理,并且如果有效,此行是否存在任何性能问题:
private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();
与构造函数注入相比(从dbContext到数据库的调用很多,因此每次我想使用IDbContext
都会很麻烦,因为它可能会消耗资源)?
我希望dbContext
是每个请求的实例而不是每个依赖项的实例的原因是,我已经在dbContext
对象的顶部实现了工作单元模式。
控制器中的普通方法如下:
public ActionResult DoSth()
{
using(var unitOfWork = UnitOfWorkManager.NewUnitOfWork())
{
//do stuff
try
{
unitOfWork.Commit();
return View();
}
catch(Exception e)
{
unitOfWork.RollBack();
LoggerService.Log(e);
return View();
}
}
}
如果此方法正常,那么我还要担心另一个问题。因此,如果我可以使我的服务成为每个生命周期的实例(,除了DbContext ),那么对服务内部的每个方法应用async-await使其成为非阻塞方法是否存在任何问题。我要问的是,对于dbContext
实例,使用async-await是否存在任何问题,因此,例如,我会有这样的事情:
public async MyModel GetMyModel()
{
var result = //await on a new task which will use dbcontext instance here
return Mapper.Map<MyModel>(result);
}
任何建议或建议都非常感谢!
答案 0 :(得分:1)
我会从远处解决这个问题。
有些建筑选择可以使您的生活更轻松。在Web开发中,将应用程序设计为具有无状态服务层(所有状态都保留在DB中)并符合一个HTTP请求,一个业务操作原则(换句话说,一种针对一种控制器动作的服务方法。
我不知道您的体系结构如何(您的帖子中没有足够的信息来确定),但是可能满足我上面描述的标准。
在这种情况下,很容易决定选择哪个组件寿命:DbContext和服务类可以是临时的(在Autofac术语中是 InstancePerDependency ),也可以是每个请求( InstancePerRequest ) -没关系。关键是它们具有相同的生存期,因此完全不会出现圈养依赖性的问题。
上述内容的进一步含义:
您可以在服务类中仅使用ctor注入而不必担心。 (无论如何,在研究诸如lifetime scopes and IOwned<T>之类的生命周期控制可能性之后,服务定位器模式将是最后的选择。)
EF本身通过 SaveChanges 实现工作单元模式,适用于大多数情况。实际上,仅当基于某种原因的事务处理不能满足您的需求时,才需要通过EF实现UoW。这些是非常特殊的情况。
[...]是否存在将async-await应用于内部的每个方法的任何问题 服务以使其成为非阻塞方法。
如果您一直一致地应用异步等待模式(我的意思是所有异步操作都在等待),直接应用于您的控制器动作(返回 Task
答案 1 :(得分:0)
答案一如既往地取决于...在以下情况下,此配置可以正常工作
:我个人只是建议做任何依赖于DbContext(直接或间接)InstancePerRequest的事情。瞬变也可以。您绝对希望一个工作单元中的所有内容都使用相同的DbContext。否则,使用Entity Framework的一级缓存,您可能会拥有不同的服务来检索相同的数据库记录,但是如果它们未使用相同的DbContext,则会对不同的内存中副本进行操作。在这种情况下,最后一次更新将获胜。
我不会在MyService中引用您的容器,只需构造函数将其注入即可。在您的域或业务逻辑中的容器引用应谨慎使用,并且只能作为最后的选择。