c# - 在运行作业的应用程序中使用中间件的最佳方法
问题描述
我有一个从外部 API 调用端点的服务。我开发了一个自定义中间件,用于处理来自这些 API 调用的可能异常并记录它们。但是,尽管中间件在Invoke 方法中包含了 try 和 catch 块,但在catch 块捕获到异常后,我的应用程序的流程会被中断。尽管应用程序继续运行,但流程只是结束了。由于此应用程序正在执行同步数据的作业,因此我需要继续流程(并记录可能的异常,正如我所提到的)。
任何人都已经经历过这种情况或有任何线索如何使流程继续?有没有更好的方法来做到这一点?我完全愿意接受建议,拜托。
这是我的代码:
public class ApiException
{
private readonly RequestDelegate _next;
private readonly ILogger<ApiException> _logger;
private readonly ApiExceptionOptions _options;
public ApiException(ApiExceptionOptions options, RequestDelegate next,
ILogger<ApiException> logger)
{
_next = next;
_logger = logger;
_options = options;
}
public async Task Invoke(HttpContext context /* other dependencies */)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
ApiError error = _options.AddResponseDetails?.Invoke(exception)
?? ApiErrorFactory.New(exception);
LogApiException(exception, error);
return CreateResponse(context, error);
}
private static Task CreateResponse(HttpContext context, ApiError error)
{
var result = JsonSerializer.Serialize(error,
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)error.Status;
return context.Response.WriteAsync(result);
}
private void LogApiException(Exception exception, ApiError error)
{
var innerExMessage = GetInnermostExceptionMessage(exception);
var level = _options.DetermineLogLevel?.Invoke(exception) ?? GetLogLevel(exception);
_logger.Log(level, exception, "ERROR: {message} -- {ErrorId}.", innerExMessage, error.Id);
}
private static LogLevel GetLogLevel(Exception exception) =>
exception switch
{
InvalidInputException _ => LogLevel.Warning,
_ => LogLevel.Error
};
private string GetInnermostExceptionMessage(Exception exception)
{
if (exception.InnerException != null)
return GetInnermostExceptionMessage(exception.InnerException);
return exception.Message;
}
}
public class ApiExceptionOptions
{
public Func<Exception, ApiError> AddResponseDetails { get; set; }
public Func<Exception, LogLevel> DetermineLogLevel { get; set; }
}
public static class ApiErrorFactory
{
public static ApiError New(Exception exception) =>
exception switch
{
InvalidInputException e => new ApiError
{
Details = e.Details,
Message = e.Message,
Status = BadRequest
},
_ => new ApiError()
};
}
public class ApiError
{
public static string DefaultErrorMessage = "Erro no processamento da requisição.";
public string Id { get; } = Guid.NewGuid().ToString();
public HttpStatusCode Status { get; set; } = HttpStatusCode.InternalServerError;
public string Title { get; set; } = "API Error";
public string Message { get; set; } = DefaultErrorMessage;
public IDictionary<string, object> Details { get; set; } = new Dictionary<string, object>();
}
public static class ApiExceptionExtensions
{
public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder)
{
var options = new ApiExceptionOptions();
return builder.UseMiddleware<ApiException>(options);
}
public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder,
Action<ApiExceptionOptions> configureOptions)
{
var options = new ApiExceptionOptions();
configureOptions(options);
return builder.UseMiddleware<ApiException>(options);
}
}
解决方案
推荐阅读
- r - R为方差分析计算添加csv填充
- jenkins - 从 Jenkins "sh" 到 groovy
- r - 在 x 轴的刻度内使用 stat_summary (geom = 'line') 连接表示
- c - 声明一个静态函数,但在 C 中不使用“static”关键字来实现它?
- c++ - 如何使用 C++ 内置函数将二维数组转换为最小堆?
- java - 如何将基本数据(如字符串)从 Android Studio 发送到 Tomcat 服务器?
- django - Django:棉花糖没有序列化嵌套的一对多关系
- python - 分解包含数字的非嵌套列表列
- excel - VBA Excel在打印PDF时隐藏带有某些名称的工作表
- xonsh - xonsh“which”等价物 - 如何测试(子进程模式)命令是否可用?