您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

ExceptionMiddleware.cs 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using Diligent.WebAPI.Contracts.Exceptions;
  2. using Diligent.WebAPI.Contracts.Models;
  3. using Microsoft.AspNetCore.Mvc;
  4. using Microsoft.Extensions.Options;
  5. using Newtonsoft.Json;
  6. using Newtonsoft.Json.Serialization;
  7. using System.Diagnostics;
  8. using System.Net;
  9. using System.Runtime.Serialization;
  10. namespace Diligent.WebAPI.Host.Middlewares
  11. {
  12. [ExcludeFromCodeCoverage]
  13. public class DiligBadRequestException : Exception
  14. {
  15. public const string ExceptionMessage = "Bad request from custom middleware";
  16. public const string ExceptionCode = "DiligBadRequestException";
  17. public const HttpStatusCode HttpResponseCode = HttpStatusCode.BadRequest;
  18. public DiligBadRequestException() : base(ExceptionMessage) { }
  19. public DiligBadRequestException(string message) : base(message) { }
  20. public DiligBadRequestException(string message, Exception innerException) : base(message, innerException) { }
  21. public DiligBadRequestException(SerializationInfo info, StreamingContext context) : base(info, context) { }
  22. }
  23. [ExcludeFromCodeCoverage]
  24. public class DiligExceptionMiddleware
  25. {
  26. private readonly RequestDelegate _next;
  27. private readonly ILogger<DiligExceptionMiddleware> _logger;
  28. private readonly IWebHostEnvironment _env;
  29. private readonly ApiBehaviorOptions _options;
  30. public DiligExceptionMiddleware(RequestDelegate next, ILogger<DiligExceptionMiddleware> logger, IWebHostEnvironment env, IOptions<ApiBehaviorOptions> options)
  31. => (_next, _logger, _env, _options) = (next, logger, env, options.Value);
  32. public async Task InvokeAsync(HttpContext httpContext)
  33. {
  34. try
  35. {
  36. await _next(httpContext);
  37. }
  38. // Some custom Exceptions
  39. catch (EntityNotFoundException ex)
  40. {
  41. _logger.LogError(ex, DiligBadRequestException.ExceptionMessage);
  42. await HandleExceptionAsync(httpContext, ex, DiligBadRequestException.ExceptionMessage, HttpStatusCode.NotFound);
  43. }
  44. catch (Exception ex)
  45. {
  46. // Better solution is to use switch statement
  47. if(HasInternalExceptionOfType<DiligBadRequestException>(ex))
  48. {
  49. _logger.LogError(ex, DiligBadRequestException.ExceptionMessage);
  50. await HandleExceptionAsync(httpContext, ex, DiligBadRequestException.ExceptionMessage, DiligBadRequestException.HttpResponseCode);
  51. }
  52. else
  53. {
  54. await HandleSomethingWentWrongAsync(httpContext, ex);
  55. }
  56. }
  57. }
  58. private async Task HandleSomethingWentWrongAsync(HttpContext httpContext, Exception ex)
  59. {
  60. _logger.LogError(ex, "Something went wrong");
  61. await HandleExceptionAsync(httpContext, ex);
  62. }
  63. private bool HasInternalExceptionOfType<T>(Exception e)
  64. {
  65. if(e.InnerException != null)
  66. {
  67. return e is T || HasInternalExceptionOfType<T>(e.InnerException);
  68. }
  69. return e is T;
  70. }
  71. private Task HandleExceptionAsync(HttpContext context, Exception exception, string? message = null, HttpStatusCode? responseCode = null)
  72. {
  73. context.Response.ContentType = "application/json";
  74. context.Response.StatusCode = (int)(responseCode ?? HttpStatusCode.InternalServerError);
  75. string type = null;
  76. if (_options.ClientErrorMapping.TryGetValue(context.Response.StatusCode, out var clientErrorData))
  77. {
  78. type = clientErrorData.Link;
  79. }
  80. var errorTitle = message ?? (_env.IsDevelopment() ? exception.Message : "Internal server error");
  81. var errorMessage = _env.IsDevelopment() ? exception.StackTrace : "Something went wrong" ;
  82. var serializerSettings = new JsonSerializerSettings
  83. {
  84. ContractResolver = new CamelCasePropertyNamesContractResolver()
  85. };
  86. var resultError = new ResultError(errorTitle);
  87. var httpResultError = new HttpResultError()
  88. {
  89. ErrorMessage = errorMessage,
  90. ErrorCode = responseCode ?? HttpStatusCode.InternalServerError
  91. };
  92. resultError.AddCustomError(httpResultError);
  93. var responseString = JsonConvert.SerializeObject(
  94. new BaseResult<Exception>
  95. {
  96. // Type = type,
  97. // TraceId = Activity.Current?.Id ?? context?.TraceIdentifier,
  98. IsSuccess = false,
  99. Errors = { resultError }
  100. }, serializerSettings);
  101. return context.Response.WriteAsync(responseString);
  102. }
  103. }
  104. [ExcludeFromCodeCoverage]
  105. public static class DiligExceptionMiddlewareExtensions
  106. {
  107. public static IApplicationBuilder UseDiligExceptionHandler(this IApplicationBuilder app)
  108. {
  109. return app.UseMiddleware<DiligExceptionMiddleware>();
  110. }
  111. }
  112. }