Injecting Services in a Long running async Task in ASP.NET Core

Sriram Kumar Mannava
2 min readJan 28, 2025

--

Sometimes you may want to write an endpoint that does a long running process (A fire and forget call that internally runs a long running Stored Procedure for e.g) on an endpoint hit.

// Example: Assuming stored procedure is named "MyStoredProcedure"
await dbContext.Database.ExecuteSqlRawAsync("EXEC MyStoredProcedure");

A simple approach to this is to place that database call inside a Task.Run() which runs the call in a separate thread and then let the endpoint return a generic success response.

[HttpGet("run-procedure")]
public IActionResult RunProcedure()
{
Task.Run(async () =>
{
await _myService.RunStoredProcedureAsync();
});
}

But things get messed up when you try to use injected dependencies (a database context for e.g.) inside this Task execution.

You'll end up getting this exception -

Cannot access a disposed object. Object name: 'YourDbContext'.

Why? Because all the dependencies injected via Controller are tied to the Request scope by default, so when you call a database context that is injected via Controller inside your task and then return the response, the Request is disposed and so is the scope.

So what's the alternative? Use an IServiceScopeFactory to create a custom scope inside the task and then inject the context from there.

using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;

public interface IMyService
{
Task RunStoredProcedureAsync();
}

public class MyService : IMyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;

public MyService(IServiceScopeFactory serviceScopeFactory)
{
_serviceScopeFactory = serviceScopeFactory;
}

public async Task RunStoredProcedureAsync()
{
using var scope = _serviceScopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();

// Example: Assuming stored procedure is named "MyStoredProcedure"
await dbContext.Database.ExecuteSqlRawAsync("EXEC MyStoredProcedure");
}
}

In this approach, the scope exists until the task is complete and so you won't encounter this exception again.

Long Running Task with DI - Complete Example

--

--

Sriram Kumar Mannava
Sriram Kumar Mannava

Written by Sriram Kumar Mannava

I make Full Stack Development Easy for You | Full Stack .NET Dev | 3× AWS Certified | Blogger

No responses yet