使用Autofac管理范围在每次请求后正确调用EF SaveChanges

时间:2015-05-10 23:25:33

标签: entity-framework owin autofac middleware

我希望在每个请求结束时在我的数据库上下文中将SaveChanges项目的基础结构放入其中。

所以我创建了一个简单的Owin中间件

app.Use(async (ctx, req) => {
     await req();
     var db = DependencyResolver.Current.GetService<MyDbContext>();
     await db.SaveChangesAsync();
});

这不起作用并抛出错误

  

无法解析实例,并且无法从此LifetimeScope创建嵌套生命周期,因为它已经被处理掉了。

如果我在完成请求之前解析db

app.Use(async (ctx, req) => {
     var db = DependencyResolver.Current.GetService<MyDbContext>();
     await req();
     await db.SaveChangesAsync();
});

它不会抛出错误但它也不起作用(因为更改没有保存到数据库中,并且在调试器中查看数据库显示DbSet&#39 ; Local属性抛出InvalidOperationException有关它的处置。

我尝试使用和不使用异步,在autofac配置(app.UseAutofacMiddleware(container))之前和之后注册中间件并直接从Owin环境解析LifetimeScope。所有这些都给了我相同的结果。

我之前使用Structuremap做过类似的事情,但似乎无法找到使Autofac发挥得更好的正确方法。

1 个答案:

答案 0 :(得分:1)

史蒂文说你不应该处理请求,因为你不能确定你是否真的要在那里提交,除非你从DbContext中抽象你的UoW并在那里保留一个成功属性,检查是否处置并有条件地承诺。

对于您的具体问题,有两点需要澄清。

  1. DbContext或UoW需要在InstancePerRequest()
  2. 中注册
  3. 不应使用Owin中间件,而应使用OnRelease(context =&gt; context.SaveMyChangesIfEverythingIsOk())原生Autofac API
  4. 例如,这就是RavenDb的样子

       builder.Register(x =>
            {
                var session = x.Resolve<IDocumentStore>().OpenAsyncSession();
                session.Advanced.UseOptimisticConcurrency = true;
                return session;
            })
                .As<IAsyncDocumentSession>()
                .InstancePerRequest()
                .OnRelease(x =>
                {
                    x.SaveChangesAsync();
                    x.Dispose();
                });