.NET Core 7中PostAsync后DbContext被释放引发对象已处置错误排查
根本原因
核心问题是控制器的StartFlightFollowing方法使用了async void。在ASP.NET Core中,标记为async void的控制器方法会被框架视为"火并忘记"的操作:框架不会等待方法内的异步操作完成,当第一个await(也就是await WriteLogRecord(-103z))执行完毕后,就会认为请求处理结束,随即释放当前请求作用域内的所有依赖服务——包括注入的GliderFFContext。
等后续的await client.GetAsync(url)异步操作完成后,再调用WriteLogRecord(-104)时,DbContext已经被释放,自然会抛出"对象已处置"错误。
而你用WebClient的同步DownloadString方法时,整个方法是同步执行的,框架会等待方法完全执行完毕才会释放DbContext,所以不会出现问题。
修复步骤
1. 把控制器异步方法的返回值从async void改为async Task
ASP.NET Core要求控制器的异步方法必须返回Task或Task<IActionResult>,这样框架才会等待所有异步操作完成后再结束请求、释放资源。
2. 将WriteLogRecord改为异步方法
使用EF Core的异步APISaveChangesAsync替代同步的SaveChanges,符合异步编程最佳实践,避免阻塞线程。
3. (推荐)用IHttpClientFactory管理HttpClient生命周期
不要在方法内直接实例化HttpClient,避免频繁创建销毁导致的套接字资源耗尽问题。
修改后的核心代码
FlightFollowController 修正版
using DBContext_test.DBContext; using DBContext_test.Models; using System.Net.Http; namespace DBContext_test.Controllers { public class FlightFollowController : BaseController { private readonly IHttpClientFactory _httpClientFactory; // 注入IHttpClientFactory public FlightFollowController(GliderFFContext db, IHttpClientFactory httpClientFactory) : base(db) { _httpClientFactory = httpClientFactory; } // 把async void改为async Task public async Task StartFlightFollowing() { string url = "https://catfact.ninja/fact"; var client = _httpClientFactory.CreateClient(); try { await WriteLogRecord(88, "Dispose find check -103z"); HttpResponseMessage response = await client.GetAsync(url); await WriteLogRecord(88, "Dispose find check -104"); } catch (Exception ex) { // 不要吞掉异常,记录下来方便排查 await WriteLogRecord(99, $"操作出错: {ex.Message}"); } } // 改为异步方法,使用SaveChangesAsync public async Task WriteLogRecord(int recType, string summary) { FFActionLogs logEntry = new FFActionLogs(); logEntry.ActionTime = DateTime.Now; logEntry.RecordType = recType; logEntry.Summary = summary; _db.FFActionLogs.Add(logEntry); await _db.SaveChangesAsync(); } } }
Program.cs 添加HttpClient注册
在builder.Services.AddControllersWithViews();之后添加:
builder.Services.AddHttpClient();
验证效果
修改后,框架会等待StartFlightFollowing内所有异步操作完成(包括两次日志写入和HTTP请求),再释放DbContext,不会再出现"对象已处置"错误。
内容的提问来源于stack exchange,提问作者Brian.S

