I am using .NET Core 3.1. I want to run some background processing without user having to wait for it to finish (it takes about 1 minute). Therefore, I used Task.Run like this:
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(); } } } I recieve the following exception in marked line:
System.ObjectDisposedException: 'Cannot access a disposed object. Object name: 'IServiceProvider'.' Why does this happen? I used custom constructor (and not scope.ServiceProvider.GetRequiredService<MyDbContext>()) for MyDbContext because I need to save one additional propery (username) for later use in overriden methods.
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 } What am I doing wrong?
MyServiceusage ? Is it created in the controller? Asp.Net creates new container scope for each incoming request. It means that container from the scope is disposed when controller's method returns the result. This explains theIServiceProvider disposederror you have. This may cause ctor object instances to be disposed by the container while certain task continues to use those instances.MyServiceis injected in the controller constructor. Controller then callsawait _myService.CreatePostAsync(...). What should I do to avoid this error?Task.Runin a web app. There is no point. It allows the current thread to be returned to the pool, but simply pulls out another in its place from that same pool. Since all requests are serviced from that same threadpool, all you're doing is cutting your total available request throughput.