Можно ли перехватывать ошибки, выдаваемые промежуточным программным обеспечением после выполнения действия контроллера?
Я вызываю 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;
}
}
Таким образом, он будет запущен, и возникнет любое исключение, в то время как все еще можно изменить вывод и выдать сообщение об ошибке.