ASP.NET 核心中的 DbContext 抛出 System.ObjectDisposedException

DbContext in ASP.NET Core throws System.ObjectDisposedException

我正在 ASP.NET Core 应用程序中使用 EF Core 将 Todo 模型保存到数据库。 但是当我尝试使用 Console.Writeline 打印成功消息时,它会抛出 System.ObjectDisposedException

这是完整的应用程序github code link

这是 ToDo 模型:

public class Todo
{
    public int Id { get; set; }

    [Required]
    [MaxLength(10)]
    public string Title { get; set; }

    public bool IsCompleted { get; set; } = false;
}

这是抛出异常的业务逻辑。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ToDoApp.Models;
using ToDoApp.Data;

namespace ToDoApp
{
    public class ToDoService
    {
        readonly ToDoContext _context;

        public ToDoService(ToDoContext context)
        {
            _context = context;
        }

        public async Task<int> CreateToDo(CreateToDoBindingModel input)
        {
            Todo todo = new()
            {
                Title = input.Title,
                IsCompleted = input.IsCompleted
            };

            _context.Add(todo);
            await _context.SaveChangesAsync();
            Console.WriteLine("Successfully saved todo.");
            return task.Id;
        }
    }
}

异常详情:

System.ObjectDisposedException
  HResult=0x80131622
  Message=Cannot access a disposed context instance. A common cause of this error is disposing a context instance 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 instance, or wrapping it 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: 'ToDoContext'.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()

为什么 Console.Writeline 抛出异常?

编辑: 这是 ToDoContext:

    public class ToDoContext: DbContext
    {
        public ToDoContext(DbContextOptions<ToDoContext> options)
        : base(options)
        { }

        public DbSet<Todo> Todos { get; set; }
    }

在 Startup.cs 中的注册方式如下:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();

            var connectionString = Configuration["ConnectionString"];
            services.AddDbContext<ToDoContext>(options => options.UseNpgsql(connectionString));

            services.AddScoped<ToDoService>();
        }

这是完整的应用程序github code link

问题出在您的这部分代码中:

 public IActionResult OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            Task<int> id =  _service.CreateTask(Input);//<--- this line
            return RedirectToPage("Index");
        }

在调用 createTask 后,returns 一个任务意味着尚未完成,您不必等待它完成,当调用 RedirectToPage 当前请求完成时。因为您的服务和 dbcontext 添加到具有 Scope 生命周期的 DI,这意味着对象的生命周期在请求期间,当请求完成时该对象将被释放。

所以为了解决问题,只需使用这种方式:

 public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            int id = await _service.CreateTask(Input);
            return RedirectToPage("Index");
        }