【发布时间】:2020-07-21 18:07:10
【问题描述】:
我正在使用 .NET Core 3.1。我想运行一些后台处理,而无需用户等待它完成(大约需要 1 分钟)。因此,我这样使用Task.Run:
public class MyController : Controller
{
private readonly IMyService _myService;
public MyController(IMyService myService)
{
_myService = myService;
}
public async Task<IActionResult> Create(...)
{
await _myService.CreatePostAsync(...);
return View();
}
}
public class MyService : IMyService
{
private readonly MyDbContext _dbContext;
private readonly IServiceScopeFactory _scopeFactory;
public MyService(MyDbContext dbContext, IServiceScopeFactory scopeFactory)
{
_dbContext = dbContext;
_scopeFactory = scopeFactory;
}
public async Task CreatePostAsync(Post post)
{
...
string username = GetUsername();
DbContextOptions<MyDbContext> dbOptions = GetDbOptions();
Task.Run(() => SaveFiles(username, dbOptions, _scopeFactory));
}
private void SaveFiles(string username, DbContextOptions<MyDbContext> dbOptions, IServiceScopeFactory scopeFactory)
{
using (var scope = scopeFactory.CreateScope())
{
var otherService = scope.ServiceProvider.GetRequiredService<IOtherService>();
var cntxt = new MyDbContext(dbOptions, username);
Post post = new Post("abc", username);
cntxt.Post.Add(post); <----- EXCEPTION
cntxt.SaveChanges();
}
}
}
我在标记的行中收到以下异常:
System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'IServiceProvider'.'
为什么会这样?我为 MyDbContext 使用了自定义构造函数(而不是 scope.ServiceProvider.GetRequiredService<MyDbContext>()),因为我需要保存一个额外的属性(用户名)以供以后在重写方法中使用。
public partial class MyDbContext
{
private string _username;
private readonly DbContextOptions<MyDbContext> _options;
public DbContextOptions<MyDbContext> DbOptions { get { return _options; } }
public MyDbContext(DbContextOptions<MyDbContext> options, string username) : base(options)
{
_username = username;
_options = options;
}
... other overriden methods
}
我做错了什么?
【问题讨论】:
-
MyService的用法是什么?它是在控制器中创建的吗? Asp.Net 为每个传入请求创建新的容器范围。这意味着当控制器的方法返回结果时,作用域中的容器被释放。这解释了您遇到的IServiceProvider disposed错误。这可能会导致 ctor 对象实例被容器释放,而某些任务会继续使用这些实例。 -
是的,
MyService被注入到控制器构造函数中。然后控制器调用await _myService.CreatePostAsync(...)。我应该怎么做才能避免这个错误? -
我更新了问题,使其也包含控制器部分。
-
你几乎不应该在网络应用程序中使用
Task.Run。无关紧要。它允许将当前线程返回到池中,但只是从同一个池中拉出另一个线程。由于所有请求都由同一个线程池提供服务,因此您所做的只是减少可用请求的总吞吐量。
标签: c# entity-framework asp.net-core dependency-injection