Можно ли перехватывать ошибки, выдаваемые промежуточным программным обеспечением после выполнения действия контроллера?

Я вызываю UseExceptionHandler для обработки ошибок. Это работает нормально, но не для ошибок, выдаваемых другим (зарегистрированным впоследствии) промежуточным программным обеспечением.

Промежуточное программное обеспечение, исключения которого мне нужно обрабатывать, — это TransactionMiddleware. Что он делает, так это сохраняет любые изменения в базе данных после успешного завершения вызова действия. Чтобы было ясно - он не просто фиксирует транзакцию, но также запускает все вставки: s / update: s и т. д. Это может привести к сбою, например, из-за ограничений базы данных. (Есть и другие причины не завершать транзакцию, но они не включены здесь. Простое упоминание об этом для объяснения того, что более ранние вызовы базы данных и сокращение TransactionMiddleware до простой фиксации не помогут.)

Есть ли способ НЕ запускать ответ до того, как это промежуточное программное обеспечение выполнит свой полный курс?

Моя программа.cs

      var builder = WebApplication.CreateBuilder(args);
new Startup(builder.Configuration).ConfigureServices(builder.Services);

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        // await ExcludedCode()...
    });
});

app.UseSwagger()
    .UseSwaggerUI();

app.UseRouting()
    .UseCors()
    .UseAuthentication()
    .UseAuthorization()
    .UseMiddleware<LanguageMiddleWare>()
    .UseMiddleware<TransactionMiddleWare>()
    .UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

app.Run();

Мой (упрощенный) класс TransactionMiddleWare

          public class TransactionMiddleWare
    {
        private readonly RequestDelegate next;

        public TransactionMiddleWare(RequestDelegate next)
        {
            this.next = next;
        }

        public async Task Invoke(HttpContext context, IDataContext dataContext)
        {
            try
            {
                await next(context);
            }
            catch (PartialExecutionException) 
            {
                this.Commit(context, dataContext);
                throw;
            }
            this.Commit(context, dataContext);
        }

        private void Commit(HttpContext context, IDataContext dataContext)
        {
            if (this.ShouldTransactionCommited(context))
                dataContext.SaveChanges();
            else
                throw new Exception("Exception example for clarity."); 
        }

        private bool ShouldTransactionBeCommited(HttpContext context)
        {
            return true; // Actual code omitted for brevity.
        }
    }

Пример того, как мои контроллеры возвращают данные (без особых вещей):

          [ApiController]
    [Route("advertisment")]
    public class AdvertismentController : ControllerBase
    {
        private readonly IAdvertismentService advertismentService;
        private NLog.ILogger log;

        public AdvertismentController(
            IAdvertismentService advertismentService)
        {
            this.log = LogManager.GetCurrentClassLogger();
            this.advertismentService = advertismentService;
        }

        [HttpPost]
        public Result<Guid> Create([FromForm] CreateAdvertismentMultipartFormModel request)
        {
            var id = this.advertismentService.Create(request);
            return new Result<Guid> { Data = id };
        }
    }

1 ответ

Вот что у меня получилось. Изменение в классе TransactionMiddleWare:

              public async Task Invoke(HttpContext context, IDataContext dataContext)
        {
            context.Response.OnStarting(state => {
                this.Commit(context, dataContext);
                return Task.CompletedTask;
            }, context);

            try
            {
                await next(context);
                this.Commit(context, dataContext);
            }
            catch (PartialExecutionException)
            {
                this.Commit(context, dataContext);
                throw;
            }
        }

Таким образом, он будет запущен, и возникнет любое исключение, в то время как все еще можно изменить вывод и выдать сообщение об ошибке.

Другие вопросы по тегам