asp.net core custom exception processing middleware
Intro
Global exception handling in asp.net core, it is sometimes not possible to meet our needs, you may need your own custom middleware handled, recently encountered a problem, there are some exceptions, do not want to log errors, the key is canceled due to user requests TaskCanceledException
and OperationCanceledException
anomalies. Because my ERROR level log output to the Sentry, sentry exceptions will automatically send e-mail alert, if some unnecessary mistakes, naturally do not need to log errors, and instead want a custom exception handling middleware own exception handling not the exception handling exception processing directly to the asp.net core.
Request cancellation
Request canceled due to abnormal:
asp.net core introduced HttpContext.RequestAborted
to monitor the user cancels the request (actual test down, not every time the trigger, not figure out how a 100% trigger), you can use HttpContext.RequestAborted
to when the user cancels the request processing logic interrupts the background, avoid unnecessary business process, gives the following example of a use, sample source code
, more detailed information can be found Byron's this interrupt request to find out
[HttpGet]
public async Task<IActionResult> GetAsync(string keyword, int pageNumber = 1, int pageSize = 10)
{
Expression<Func<Notice, bool>> predict = n => true;
if (!string.IsNullOrWhiteSpace(keyword))
{
predict = predict.And(n => n.NoticeTitle.Contains(keyword));
}
var result = await _repository.GetPagedListResultAsync(x => new
{
x.NoticeTitle,
x.NoticeVisitCount,
x.NoticeCustomPath,
x.NoticePublisher,
x.NoticePublishTime,
x.NoticeImagePath
}, queryBuilder => queryBuilder
.WithPredict(predict)
.WithOrderBy(q => q.OrderByDescending(_ => _.NoticePublishTime))
, pageNumber, pageSize, HttpContext.RequestAborted); // 直接使用 HttpContext.RequestAborted
return Ok(result);
}
// 在 Action 方法中声明 CancellationToken,asp.net core 会自动将 `HttpContext.RequestAborted` 绑定到 CancellationToken 对象
[HttpGet]
public async Task<IActionResult> GetAsync(CancellationToken cancellationToken)
{
var result = await _repository.GetResultAsync(p => new
{
p.PlaceName,
p.PlaceIndex,
p.PlaceId,
p.MaxReservationPeriodNum
}, builder => builder
.WithPredict(x => x.IsActive)
.WithOrderBy(x => x.OrderBy(_ => _.PlaceIndex).ThenBy(_ => _.UpdateTime)), cancellationToken);
return Ok(result);
}
Exception Handling Middleware
Exception Handling Middleware Source:
public class CustomExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly CustomExceptionHandlerOptions _options;
public CustomExceptionHandlerMiddleware(RequestDelegate next, IOptions<CustomExceptionHandlerOptions> options)
{
_next = next;
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (System.Exception ex)
{
var logger = context.RequestServices.GetRequiredService<ILoggerFactory>()
.CreateLogger<CustomExceptionHandlerMiddleware>();
if (context.RequestAborted.IsCancellationRequested && (ex is TaskCanceledException || ex is OperationCanceledException))
{
_options.OnRequestAborted?.Invoke(context, logger);
}
else
{
_options.OnException?.Invoke(context, logger, ex);
}
}
}
}
public class CustomExceptionHandlerOptions
{
public Func<HttpContext, ILogger, Exception, Task> OnException { get; set; } =
async (context, logger, exception) => logger.LogError(exception, $"Request exception, requestId: {context.TraceIdentifier}");
public Func<HttpContext, ILogger, Task> OnRequestAborted { get; set; } =
async (context, logger) => logger.LogInformation($"Request aborted, requestId: {context.TraceIdentifier}");
}
You can configure CustomExceptionHandlerOptions
an error log to implement custom exception handling logic, the default request will cancel a record level log Information, other exceptions will record a level of Error
When you encounter can be configured by the following example request cancellation of doing nothing abnormal
service.Config(options=>
{
options.OnRequestAborted = (context, logger) => Task.CompletedTask;
});