我有一个自定义中间件,其目的是订阅EF Core dbcontext事件并跟踪实体发生的更改。中间件在每个请求开始时将我的InteractionService实例化为范围实例。这就是我的中间件的样子:
public static IApplicationBuilder UseDbContextActivityTracker<TContext>(this IApplicationBuilder app)
where TContext : DbContext
{
app.Use(async (context, next) =>
{
var service = context.RequestServices.GetRequiredService<InteractionService<TContext>>();
await next.Invoke();
service.PersistLogs();
});
return app;
}
这就是我在Startup类的Configure方法中使用中间件的方法:
options.UseDbContextActivityTracker<ApplicationDbContext>();
在我的InteractionService的构造函数中,我通过DI得到了dbcontext的引用,我订阅了这些事件:
public InteractionService(TContext context)
{
this.context = context;
this.context.ChangeTracker.StateChanged += ChangeTracker_StateChanged;
}
在请求期间收听dbContext发生的事件时,我将相关信息存储到我自己的实体中,并且效果很好。但是,在请求结束时,我想保存对数据库的更改。我尝试使我的InteractionService类IDisposable,并在Dispose方法中,我调用另一个DbContext,我在其中保存我的实体。正如所料,我收到错误“连接已关闭”。请求完成后,将实体保存到数据库的正确位置是什么?
@Panagiotis Kanavos向我指出了正确的方向。我的问题是如何获得一个适当的作用域DbContext来编写更改。在我的InteractionService
中,而不是通过构造函数注入DbContext,我使用serviceProvider手动创建它。我改变了这个:
public CampusAxessInteractionStore(MyDbContext context)
{
this.context = context;
}
对此:
public CampusAxessInteractionStore(IServiceProvider serviceProvider)
{
var scopeResolver = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope();
this.context = scopeResolver.ServiceProvider.GetRequiredService<CampusAxessDbContext>();
}
现在节约工作。我仍然不确定这是否是正确的方法。如果有人可以指出我应该如何正确完成这一点,我会删除我的答案,并将你的答案标记为正确。