简体   繁体   English

Asp.net 内核:无法访问已处置的 object。 此错误的常见原因是处理从依赖注入中解析的上下文

[英]Asp.net core: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection

I am developing a web api project.我正在开发一个 web api 项目。 Nowadays, I have a problem when calling an endpoint.如今,我在调用端点时遇到了问题。 I do not constantly get an error when calling this endpoint, for example if I am calling 30 times a day, I get this error 2 times.调用此端点时,我不会经常收到错误,例如,如果我每天调用 30 次,我会收到 2 次此错误。 This endpoint just select the data and working async.这个端点只是 select 数据和异步工作。 I tried all the solutions I found on the internet but it didn't work.我尝试了在互联网上找到的所有解决方案,但没有奏效。 Error: Cannot access a disposed object.错误:无法访问已处置的 object。 A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application.此错误的一个常见原因是释放从依赖注入中解析的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。 This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement.如果您在上下文上调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。 If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.如果你使用依赖注入,你应该让依赖注入容器负责处理上下文实例。

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

Note: I'm using .net core 3.1注意:我使用的是 .net 核心 3.1

--UPDATE - 更新

As far as I can see from the log, the ResponseWrapperFilter class causes this error.据我从日志中可以看出,ResponseWrapperFilter class 导致了这个错误。 But since I couldn't catch this error while debugging, I couldn't find a reason.但是由于我在调试时无法捕捉到这个错误,所以我找不到原因。

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

As far as I can see from the log,the bold line is causing of the error (p.GetSetMethod().Invoke(v, new[] { CompanyIdCompany });)据我从日志中可以看出,粗线是导致错误的原因 (p.GetSetMethod().Invoke(v, new[] { CompanyIdCompany });)

As this problem only shows sporadically, a likely cause of the problem is an (accidental) spawn background operation running parallel to the request operation.由于此问题只是偶尔显示,因此问题的可能原因是与请求操作并行运行的(意外)生成后台操作。 This parallel operation has access to the request's DbContext instance.此并行操作可以访问请求的DbContext实例。

NOTE: In case the error would persist after an initial successful operation, this would be an indication that the DbContext is held captive by one of its consumers;注意:如果错误在初始成功操作后仍然存在,这表明DbContext被它的一个消费者控制; in other words, a Captive Dependency .换句话说,一个Captive Dependency

In most cases the background operation finishes before the request ends, and thus before the DbContext is disposed of.在大多数情况下,后台操作在请求结束之前完成,因此在DbContext被释放之前完成。 In some cases, however, there is a delay in that (accidental) parallel operation, causing it to access the DbContext after the request has ended, and thus after the DbContext was disposed of by ASP.NET Core.然而,在某些情况下,该(意外)并行操作存在延迟,导致它在请求结束访问DbContext ,因此在DbContext内核处理 DbContext 之后。

This might have happened because you forgot to await an asynchronous operation.这可能是因为您忘记await异步操作而发生的。 When you forget to await such operation, it starts running in parallel.当您忘记await此类操作时,它会开始并行运行。 Running such code in parallel, however, is often problematic, especially when dealing with objects such as DbContext , as they are not thread-safe.然而,并行运行这样的代码通常是有问题的,尤其是在处理诸如DbContext类的对象时,因为它们不是线程安全的。

So analyze the stack trace to find the place where you forgot to await the operation.因此分析堆栈跟踪以找到您忘记await操作的地方。 For instance:例如:

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.

相关问题 错误:无法访问已处理的对象。 此错误的一个常见原因是处理从依赖注入解决的上下文 - Error: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection 无法访问已处置的 object。 此错误的常见原因是处理从依赖注入中解析的上下文 - Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection &#39;无法访问已处理的对象。 此错误的一个常见原因是处理从依赖注入解决的上下文 - 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection .Net core/EF:无法访问已处置的 object。 此错误的常见原因是处理上下文 - .Net core/EF : cannot access a disposed object. A common cause of this error is disposing a context 无法访问已处理的对象。此错误的原因 - 与依赖注入相关的 Asp.net Core 异常 - Cannot access a disposed object.cause of this error - Asp.net Core Exception related to Dependency Injection 无法访问ASP.NET Core后台服务中的已处置对象 - Cannot access a disposed object in ASP.NET Core background service 无法访问已处置的 object Asp.net Identity Core - Cannot access a disposed object Asp.net Identity Core 无法访问已处置的 object。 Object 名称:AspNet Core/EF Core 项目中出现“IServiceProvider”错误 - Cannot access a disposed object. Object name: 'IServiceProvider' error in AspNet Core/EF Core project ASP.NET核心中第三方数据上下文的依赖注入 - Dependency Injection for third party data context in ASP.NET core 如何解决asp.net core 2.1中无法访问已处置对象? - How to solve Cannot access a disposed object in asp.net core 2.1?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM