[英]Error: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection
[英]Asp.net core: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection
我正在開發一個 web api 項目。 如今,我在調用端點時遇到了問題。 調用此端點時,我不會經常收到錯誤,例如,如果我每天調用 30 次,我會收到 2 次此錯誤。 這個端點只是 select 數據和異步工作。 我嘗試了在互聯網上找到的所有解決方案,但沒有奏效。 錯誤:無法訪問已處置的 object。 此錯誤的一個常見原因是釋放從依賴注入中解析的上下文,然后嘗試在應用程序的其他地方使用相同的上下文實例。 如果您在上下文上調用 Dispose() 或將上下文包裝在 using 語句中,則可能會發生這種情況。 如果你使用依賴注入,你應該讓依賴注入容器負責處理上下文實例。
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyContext>(options => options.UseMySql(Environment.GetEnvironmentVariable("MY_DB_CONNECTION")), ServiceLifetime.Transient);
services.DIRegisterer();
}
public static IServiceCollection DIRegisterer(this IServiceCollection services)
{
services.AddScoped<MyService>();
}
注意:我使用的是 .net 核心 3.1
- 更新
據我從日志中可以看出,ResponseWrapperFilter class 導致了這個錯誤。 但是由於我在調試時無法捕捉到這個錯誤,所以我找不到原因。
public class ResponseWrapperFilter : IActionFilter, IOrderedFilter
{
private MYContext myContext;
private IMemoryCache cache;
private readonly TimeSpan _defaultCacheTimespan = new TimeSpan(0, 5, 0);
private void FillNavigationProperties(object v, int recursionLevel)
{
if (recursionLevel > 2)
return;
if (v.GetType().FullName == "System.DateTime" || v.GetType().FullName == "System.String"
|| v.GetType().FullName == "Newtonsoft.Json.Linq.JObject")
return;
if (v != null && v.GetType().FullName.StartsWith("System.Collections.Generic.List"))
{
foreach (var x in (IList)v)
{
foreach (var y in x.GetType().GetProperties())
{
if (x.GetType().FullName == "System.DateTime" || x.GetType().FullName == "System.String"
|| x.GetType().FullName == "Newtonsoft.Json.Linq.JObject")
continue;
var prop = y.GetGetMethod().Invoke(x, null);
if (prop != null)
{
FillNavigationProperties(prop, recursionLevel + 1);
}
else
{
TryToFillNavigationProperty(x, y);
}
}
}
}
}
private void TryToFillNavigationProperty(object v, PropertyInfo p)
{
if (p.PropertyType == typeof(Company) || p.PropertyType.IsSubclassOf(typeof(Company)))
{
if (v.GetType().GetProperties().Where(_ => _.Name == p.Name + "Id").Any())
{
var CompanyId = (ulong)v.GetType().GetProperties().Where(_ => _.Name == p.Name + "Id").First().GetGetMethod().Invoke(v, null);
var cacheKey = "Company->Id->" + CompanyId.ToString();
if (cache.TryGetValue(cacheKey, out Company CompanyIdCompany))
{
p.GetSetMethod().Invoke(v, new[] { CompanyIdCompany });
}
else
{
CompanyIdCompany = myContext.Set<Company>().Where(_ => _.Id == CompanyId).FirstOrDefault();
cache.Set(cacheKey, CompanyIdCompany, _defaultCacheTimespan);
**p.GetSetMethod().Invoke(v, new[] { CompanyIdCompany });**
}
}
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception is null)
{
myContext = context.HttpContext.RequestServices.GetRequiredService<MYContext>();
cache = context.HttpContext.RequestServices.GetRequiredService<IMemoryCache>();
if (context.Result.GetType() == typeof(ObjectResult))
{
object current = ((ObjectResult)context.Result).Value;
if (current != null)
FillNavigationProperties(current, 0);
context.Result = new OkObjectResult(new MYResponse()
{
Data = current
});
}
}
}
}
據我從日志中可以看出,粗線是導致錯誤的原因 (p.GetSetMethod().Invoke(v, new[] { CompanyIdCompany });)
由於此問題只是偶爾顯示,因此問題的可能原因是與請求操作並行運行的(意外)生成后台操作。 此並行操作可以訪問請求的DbContext
實例。
注意:如果錯誤在初始成功操作后仍然存在,這表明
DbContext
被它的一個消費者控制; 換句話說,一個Captive Dependency 。
在大多數情況下,后台操作在請求結束之前完成,因此在DbContext
被釋放之前完成。 然而,在某些情況下,該(意外)並行操作存在延遲,導致它在請求結束后訪問DbContext
,因此在DbContext
內核處理 DbContext 之后。
這可能是因為您忘記await
異步操作而發生的。 當您忘記await
此類操作時,它會開始並行運行。 然而,並行運行這樣的代碼通常是有問題的,尤其是在處理諸如DbContext
類的對象時,因為它們不是線程安全的。
因此分析堆棧跟蹤以找到您忘記await
操作的地方。 例如:
public async Task DoSomethingAsync()
{
await this.DoSomethingNiceAsync();
this.DoSomethingElseAsync(); // forgot to await
}
private async Task DoSomethingElseAsync()
{
// Makes use of dbcontext
await this.dbContext.GetEntitiesAsync();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.