簡體   English   中英

嘗試在請求管道內寫入數據庫時​​出現ObjectDisposedException

[英]ObjectDisposedException when trying to write to database inside request pipeline

我正在嘗試添加一些代碼,以將每個請求的DateTime值保存到數據庫。

我向app.Use() Configure方法添加了一些代碼。

這是我的配置方法:

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”。

在每個請求上寫入數據庫的正確方法是什么?

發生這種情況是因為您使用的示波器不正確。 您正在從configure方法獲取數據庫實例。 但這在啟動時被調用一次。

您應該執行以下操作:

  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();
        });

希望此代碼段對您有所幫助。 如果您需要任何澄清,我將很樂意回答您的問題。

可以有多種方法來處理這種情況。 我會使用的一個方法是創建自定義過濾器,並使用自定義過濾器注釋方法或操作以更新用戶的上次訪問時間。

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
{
    ...
}

有關自定義過濾器的更多詳細信息

這可能是因為MyDbContext是可拋棄的,並且每次需要時都需要包裝在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)
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM