Can I call an unawaited Async method and return a response while still using the DbContext?

.net-core asp.net-core c# entity-framework-core

Question

Is it possible in .net core for a controller to call an Async method that will use a scoped DbContext but not be awaited?

Basically I want this unawaited Async method to make an http call to an external dependency, and when done, save some information to the DB, but we don’t want to await the call because the user does not need the outcome of the operation, they just need to know that the operation was started.

When the call is not awaited, the DbContext is disposed of before the operation completes because the client http request (not the http call to the external dependency) is complete. What’s the best approach to handling this without awaiting the call?

1
1
10/11/2019 5:26:36 AM

Popular Answer

There are several ways to do so. One would be to use a library like HangFire. Here is a good blog-post.

What you could also do is, to use an in-memory queue and write a hosted-service, that picks up the tasks. Within that hosted-service you can inject an instance of IServiceProvider and create a scope everytime you pick up an item from the queue.

Something like this for instance:

// BackgroundService is a base-class implementation of IHostedService
// You will find it in the package Microsoft.Extensions.Hosting.Abstractions
public class QueueWorkerService : BackgroundService
{
    private readonly IServiceProvider serviceProvider;
    // this could be anything you choose to fullfill the task!
    private readonly ISomeQueueProvider queueProvider;

    public QueueWorkerService(IServiceProvider serviceProvider, ISomeQueueProvider queueProvider)
    {
        this.serviceProvider = serviceProvider;
        this.queueProvider = queueProvider;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            if (!queueProvider.Tasks.Any())
            {
                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
                continue;
            }

            using var scope = serviceProvider.CreateScope();

            var context = scope.ServiceProvider.GetRequiredService<MyDbContext>();

            foreach (var task in queueProvider.Tasks)
            {
                // do logic 
                await context.Set<SomeEntity>().AddAsync(someObject);
            }
        }
    }
}

Keep in mind this implementation is more like pseudo-code. For the queues you could really use anything.

Edit: Here is a sample for queues in worker processes from Microsoft.

1
10/11/2019 10:04:51 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow