尝试写入请求管道内的数据库时出现ObjectDisposedException

时间:2018-02-10 09:50:10

标签: c# asp.net-core .net-core

我正在尝试添加一些代码,以便在每次请求时将DateTime值保存到数据库。

我在使用app.Use()配置方法时添加了一些代码。

这是我的配置方法:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, MyDbContext db)
{
    var appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>();

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }            

    app.UseCors(builder =>
       builder.WithOrigins(appSettings.BaseUrls.WebAllowCors)
              .AllowAnyHeader().AllowAnyMethod()
   );

    app.UseAuthentication();


    app.Use(async (context,next) =>
    {
        var id = context.User.Claims.First(x => x.Type == "sub").Value;

        var user = db.AspNetUsers.Find(id);

        user.LastAccessed = DateTime.Now;

        await db.SaveChangesAsync();

        await next();
    });

    app.UseMvc();
}

但我收到错误:

  

处理请求时发生未处理的异常。

     

ObjectDisposedException:无法访问已处置的对象。此错误的常见原因是处理从依赖项注入解析的上下文,然后尝试在应用程序的其他位置使用相同的上下文实例。如果您在上下文中调用Dispose()或将上下文包装在using语句中,则可能会发生这种情况。如果使用依赖项注入,则应该让依赖项注入容器负责处理上下文实例。   对象名称:'MyDbContext'。

在每次请求时写入数据库的正确方法是什么?

3 个答案:

答案 0 :(得分:2)

这可能发生,因为您使用的范围错误。 您正在从configure方法获取db实例。但这在启动时被称为一次。

你应该这样做:

  app.Use(async (context, next) =>
        {
            var id = context.User.Claims.First(x => x.Type == "sub").Value;
            using(var db = context.RequestServices.GetService<MyDbContext>())
            {

               var user = db.AspNetUsers.Find(id);

               user.LastAccessed = DateTime.Now;

               await db.SaveChangesAsync();
            }
            await next();
        });

希望这段代码可以帮到你。如果您需要任何澄清,我非常愿意回答您的问题。

答案 1 :(得分:0)

可以有多种方法来处理这种情况。我将使用的是创建自定义过滤器并使用自定义过滤器注释方法或操作以更新用户的上次访问时间。

public class UpdateLastAccessFilter : ActionFilterAttribute, IActionFilter
{
    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
        // TODO: Add your action filter's tasks here

        // Log Action Filter call
        using (dbEntities context = new dbEntities())
        {

            var id = context.User.Claims.First(x => x.Type == "sub").Value;

        var user = db.AspNetUsers.Find(id);

        user.LastAccessed = DateTime.Now;

        await db.SaveChangesAsync();
            OnActionExecuting(filterContext);
        }
    }
}

然后装饰需要记录访问时间的方法或控制器。

[UpdateLastAccessFilter]
public class StoreController : Controller
{
    ...
}

More Details on custom filter

答案 2 :(得分:0)

这可能是因为MyDbContext是一次性的,需要在每次需要时包装使用。

试试这个,看它是否有效:

using (var context = db)
{
    context.AspNetUsers.Find(id);
}

您可能需要对db的任何后续使用执行相同操作。

我假设在MyDbContext StartUp.cs函数中已将ConfigureService(IServiceCollection services)注册到IoC?像这样:

services.AddDbContext<MyDbContext>(options =>
    options.UseSqlServer(Configuration.GetSection("ConnectionStrings:Sql").Value)
);