ASP.NET Core MVC控制器中如何使用ApplicationDBContext?
首先直接给你结论:完全可以通过依赖注入使用全局配置的DbContext,不需要每次请求手动新建,Startup里的配置会被DI容器自动复用。你遇到的ObjectDisposedException错误,根源不在依赖注入的方式,而是你控制器Action的异步写法有问题。
错误原因分析
看你的代码,控制器里的Index和AMethod都用了async void作为返回类型:
public async void Index() { ... } public async void AMethod(string parameter) { ... }
在ASP.NET Core中,async void是异步编程的大忌——这种方法不会返回Task,ASP.NET的请求管道无法跟踪它的执行进度。当请求进来时,控制器构造函数注入的MyContext是Scoped生命周期(默认每个请求一个实例),但如果Action是async void,ASP.NET会在方法开始执行后就认为请求已经完成,提前释放掉MyContext实例。等你后续执行await _userManager.GetUserAsync(User)或者await _context.SaveChangesAsync()时,上下文已经被释放,自然就抛出了Cannot access a disposed object的错误。
解决方案
把所有异步Action的返回类型从async void改成async Task(如果需要返回视图/结果,就用async Task<IActionResult>),这样ASP.NET会正确等待异步操作完成后再结束请求、释放上下文。
另外,你的AMethod里还有个小问题:_context.MyEntity.AddAsync(parameter)的参数应该是你的实体类实例,而不是string,这里大概率是笔误,需要修正。
修正后的代码示例:
[Route("[controller]/[action]")] public class MyController : Controller { private readonly UserManager<ApplicationUser> _userManager; private readonly ILogger _logger; private readonly UrlEncoder _urlEncoder; private readonly MyContext _context; public MyController( UserManager<ApplicationUser> userManager, ILogger<ManageController> logger, UrlEncoder urlEncoder, MyContext context) { _userManager = userManager; _logger = logger; _urlEncoder = urlEncoder; _context = context; } [HttpGet] public async Task<IActionResult> Index() { var user = await _userManager.GetUserAsync(User); if (user == null) { throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'."); } // 这里可以返回视图,比如 return View(user); return Ok(user); } [HttpPost] public async Task<IActionResult> AMethod(string parameter) { // 假设你的实体类是MyEntity,这里创建实例并赋值 var newEntity = new MyEntity { SomeProperty = parameter }; await _context.MyEntity.AddAsync(newEntity); await _context.SaveChangesAsync(); return Ok("保存成功"); } }
额外说明
- DbContext的生命周期:ASP.NET Core默认把DbContext注册为Scoped服务,也就是每个HTTP请求会创建一个实例,请求结束后由DI容器自动释放。你不需要手动调用
Dispose(),也不要用using包裹注入的上下文实例,否则会导致提前释放。 - 依赖注入的正确性:你在控制器构造函数中注入
MyContext的方式是完全正确的,DI容器会自动使用你在Startup.cs(或者Program.cs,.NET 6+)中配置的数据库连接字符串等参数,不需要重复配置。
内容的提问来源于stack exchange,提问作者Anes Belfodil

