Могу ли я вызвать нежелательный метод Async и вернуть ответ, все еще используя DbContext? - PullRequest
1 голос
/ 11 октября 2019

Возможно ли в ядре .net для контроллера вызвать метод Async, который будет использовать DbContext с областью действия, но не ожидается?

По сути, я хочу, чтобы этот нежелательный метод Async выполнял вызов http для внешнегозависимости, и когда закончите, сохраните некоторую информацию в БД, но мы не хотим ждать вызова, потому что пользователю не нужен результат операции, ему просто нужно знать, что операция была запущена.

Когда вызов не ожидается, DbContext удаляется до завершения операции, потому что клиентский http-запрос (а не http-вызов внешней зависимости) завершен. Как лучше всего справиться с этим, не дожидаясь звонка?

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Есть несколько способов сделать это. Можно было бы использовать библиотеку типа HangFire. Вот хорошее сообщение в блоге .

Что вы также можете сделать, это использовать очередь в памяти и написать hosted-service , которая подхватываетзадачи. В этом размещенном сервисе вы можете внедрить экземпляр IServiceProvider и создавать область каждый раз, когда выбираете элемент из очереди.

Примерно так, например:

// 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);
            }
        }
    }
}

Сохранитьв виду, что эта реализация больше похожа на псевдокод. Для очередей вы могли бы использовать что угодно.

Редактировать: Вот образец для очередей в рабочих процессах от Microsoft.

0 голосов
/ 11 октября 2019

Нет, ты не можешь. Выход из области действия избавит вас от DBContext. После завершения вашего внешнего вызова вам необходимо снова создать DBContext / scope.

В зависимости от ваших потребностей вы можете:

  • Проверить Hangfire или MediatR - оба включают события fire-and-Forgot
  • Выполнить простое задание
Task.Run(async ()=>
{
   await MyApiCall();
   using (var scope = CreateDiScope())
   {
       var ctx = scope.ServiceProvider.GetService<MyDbContext>();
       ....
       ctx.SaveChanges()
   }
}

...