简体   繁体   English

EF Core DbContext ObjectDisposedException

[英]EF Core DbContext ObjectDisposedException

having EF core 2.2 and .net core 2.2 I am struggling with ObjectDisposedException issues like: here and here拥有 EF 核心 2.2 和 .net 核心 2.2 我正在努力解决 ObjectDisposedException 问题,例如: 这里这里

few facts:几个事实:

  • all my services are registered as Transient, same with DbContext using AddDbContext()我所有的服务都注册为瞬态,与使用AddDbContext()的 DbContext 相同
  • using DI to inject DbContext instance使用 DI 注入DbContext实例
  • all functions mentioned in stack trace are async / await堆栈跟踪中提到的所有函数都是async / await

I feel that I am missing something obvious here but I have spent already 2-3 days on this without any luck我觉得我在这里遗漏了一些明显的东西,但我已经花了 2-3 天没有任何运气

stack trace:堆栈跟踪:

Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware [8] - An unhandled exception has occurred while executing the request. System.ObjectDisposedException: Cannot access a disposed 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. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'BaseContext'.
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Internal.IDbContextDependencies.get_QueryProvider()
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ParameterExtractingExpressionVisitor..ctor(IEvaluatableExpressionFilter evaluatableExpressionFilter, IParameterValues parameterValues, IDiagnosticsLogger`1 logger, DbContext context, Boolean parameterize, Boolean generateContextAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryModelGenerator.ExtractParameters(IDiagnosticsLogger`1 logger, Expression query, IParameterValues parameterValues, Boolean parameterize, Boolean generateContextAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
   at System.Linq.AsyncEnumerable.Aggregate_[TSource,TAccumulate,TResult](IAsyncEnumerable`1 source, TAccumulate seed, Func`3 accumulator, Func`2 resultSelector, CancellationToken cancellationToken) in D:\a\1\s\Ix.NET\Source\System.Interactive.Async\Aggregate.cs:line 118
   at Sample.Infrastructure.Tasks.TagEventTypeTasks.GetAllAsync() in ~root\Sample.API\Sample.Infrastructure\Tasks\TagEventTypeTasks.cs:line 24
   at Sample.API.Helpers.GraphHelpers.GetAllTagEventTypesWithCacheAsync() in ~root\Sample.API\Sample.API\Helpers\GraphHelpers.cs:line 45
   at Sample.API.Controllers.GraphController.GetTagEventTypeTimesAsync() in ~root\Sample.API\Sample.API\Controllers\GraphController.cs:line 59
   at lambda_method(Closure , Object )
   at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
   at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

for full transparency, here are the methods mentioned in stack trace:为了完全透明,以下是堆栈跟踪中提到的方法:

GraphController.cs: GraphController.cs:

[HttpGet("tagEventTypeTimes")]
public async Task<ActionResult<List<TagEventTypeResultDto>>> GetTagEventTypeTimesAsync()
{
    return await _graphHelpers.GetAllTagEventTypesWithCacheAsync();
}

GraphHelpers.cs: GraphHelpers.cs:

public async Task<List<TagEventType>> GetAllTagEventTypesWithCacheAsync()
{
    string tagEventTypesKey = "tagEventTypes";
    List<TagEventType> tagEventTypes;
    if (!_cache.TryGetValue<List<TagEventType>>(tagEventTypesKey, out tagEventTypes))
    {
        tagEventTypes = await _tagEventTypeTasks.GetAllAsync();
        _cache.Set<List<TagEventType>>(tagEventTypesKey, tagEventTypes, _memCacheOptions);
    }

    return tagEventTypes;
}

TagEventTypeTasks.cs: TagEventTypeTasks.cs:

public class TagEventTypeTasks : ITagEventTypeTasks
{
    private readonly BaseContext _context;

    public TagEventTypeTasks(BaseContext context)
    {
        _context = context;
    }

    public async Task<List<TagEventType>> GetAllAsync()
    {
        return await _context.TagEventType.OrderByDescending(x => x.Id).AsNoTracking().ToListAsync();
    }
}

BaseContext.cs: BaseContext.cs:

public class BaseContext : DbContext
{
    private readonly ILoggerFactory _logger;

    public BaseContext(DbContextOptions<BaseContext> options, ILoggerFactory logger) : base(options)
    {
        _logger = logger;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLoggerFactory(_logger);
    }

    public DbSet<Patient> Patient { get; set; }
    public DbSet<Room> Room { get; set; }
    public DbSet<Tag> Tag { get; set; }
    public DbSet<TagEvent> TagEvent { get; set; }
    public DbSet<TagEventType> TagEventType { get; set; }
    public DbSet<TagLocation> TagLocation { get; set; }
    public DbSet<TagRegistration> TagRegistration { get; set; }
    public DbSet<User> User { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfiguration(new PatientConfiguration());
        builder.ApplyConfiguration(new TagConfiguration());
        builder.ApplyConfiguration(new TagRegistrationConfiguration());
        builder.ApplyConfiguration(new TagEventConfiguration());
        builder.ApplyConfiguration(new TagEventTypeConfiguration());
        builder.ApplyConfiguration(new TagLocationConfiguration());
        builder.ApplyConfiguration(new RoomConfiguration());
    }
}

UPDATE: added startup related code更新:添加了启动相关代码

services.AddDbToServices(Configuration.GetConnectionString("DefaultConnection"));

public static void AddDbToServices(this IServiceCollection services, string connectionString)
{
    services.AddDbContext<BaseContext>(options => options.UseFirebird(connectionString), ServiceLifetime.Transient);
}

UPDATE2更新2

added whole TagEventTypeTasks class添加了整个TagEventTypeTasks

UPDATE3更新3

added services register I am using this lib however I tried to register all services manually using AddTransient() -> also didn't help添加的服务注册我正在使用这个但是我尝试使用AddTransient()手动注册所有服务 - >也没有帮助

var assembliesToScan = new[]
{
    Assembly.GetExecutingAssembly(),
    Assembly.GetAssembly(typeof(Patient)),
    Assembly.GetAssembly(typeof(PatientTasks))
};

services
    .RegisterAssemblyPublicNonGenericClasses(assembliesToScan)
    .AsPublicImplementedInterfaces(ServiceLifetime.Transient);

This looks like a dependency injection issue.这看起来像一个依赖注入问题。

I think _graphHelpers disposes the context, and next time the action is executed the controller is using the not-transient _graphHelpers which holds on to the old, disposed context.我认为_graphHelpers处理上下文,下次执行操作时,controller 正在使用非瞬态_graphHelpers保留旧的、已处理的上下文。

It could even be the controller calling Dispose() on _graphHelpers .甚至可能是 controller 在_graphHelpers上调用Dispose()


Some DI examples一些 DI 示例

Here is a setup from Get Started with ASP.NET Core and Entity Framework 6这是ASP.NET 核心和实体框架 6 入门的设置

(...)
services.AddScoped<SchoolContext>(_ => new SchoolContext(Configuration.GetConnectionString("DefaultConnection")

Tutorial: Get started with EF Core in an ASP.NET MVC web app uses AddDbContext Please note that this example is for .NET Core 2.2, not 3.0. 教程:在 ASP.NET MVC web 应用程序中开始使用 EF Core AddDbContext注意,此示例适用于 .NET Core 2.2,而不是 3.0。

(...)
services.AddDbContext<SchoolContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

Here is the configuration from Configuring a DbContext这是来自配置 DbContext的配置

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options => options.UseSqlite("Data Source=blog.db"));
}

No DI solution无 DI 解决方案

You could use new context to fetch the data, not _context .您可以使用新上下文来获取数据,而不是_context

public async Task<List<TagEventType>> GetAllAsync()
{
    // If you want DI, then do this only Temporarily, just for a diagnosis.
    using (var db = new InverterContext("connString")) 
    {
       return await db.TagEventType.OrderByDescending(x => x.Id).AsNoTracking().ToListAsync();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM