Завершение работы Hangfire в транзакции - PullRequest
1 голос
/ 24 октября 2019

Я ищу способ глобально обернуть вызовы БД в фоновом задании Hangfire в транзакции, аналогично реализации IAsyncActionFilter в AspNetCore.

Я пытался реализовать IServerFilter, но, похоже, я не получаю один и тот же экземпляр DbContext при выполнении моего запроса в задании, поэтому транзакция всегда равна нулю. (Откат по ошибке намеренно еще не реализован.)

public class DbContextTransactionFilter : IServerFilter
{
    private readonly MyContext _dbContext;

    public DbContextTransactionFilter(MyContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void OnPerforming(PerformingContext filterContext)
    {
        Task.Run(async () => await _dbContext.BeginTransactionAsync());
    }

    public void OnPerformed(PerformedContext filterContext)
    {
        Task.Run(async () => await _dbContext.CommitTransactionAsync());
    }
}

Каков предлагаемый способ сделать это?

Редактировать 1:

Так я реализовалIAsyncActionFilter и я собираюсь сделать что-то подобное для заданий Hangfire.

public class DbContextTransactionFilter : IAsyncActionFilter
{
    private readonly MyContext _dbContext;

    public DbContextTransactionFilter(MyContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        try
        {
            await _dbContext.BeginTransactionAsync();

            var actionExecuted = await next();
            if (actionExecuted.Exception != null && !actionExecuted.ExceptionHandled)
            {
                _dbContext.RollbackTransaction();

            }
            else
            {
                await _dbContext.CommitTransactionAsync();
            }
        }
        catch (Exception)
        {
            _dbContext.RollbackTransaction();
            throw;
        }
    }
}

Редактировать 2: Вот так я регистрирую контекст БД и фильтр в классе запуска:

services.AddDbContext<MyContext>(options =>
          options.UseSqlServer(Configuration.GetConnectionString("MyDatabase")));

services.AddScoped<DbContextTransactionFilter>();

services.AddHangfire((provider, configuration) => configuration
.UseFilter(provider.GetRequiredService<DbContextTransactionFilter>())
);

services.AddHangfireServer();
...