namespace NetinaShop.Api.WebFramework.MiddleWares; public static class ExceptionHandlerMiddlewareExtensions { public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder) { return applicationBuilder.UseMiddleware(); } } public class ExceptionHandlerMiddleware { private readonly IWebHostEnvironment _env; private readonly ILogger _logger; private readonly RequestDelegate _next; public ExceptionHandlerMiddleware( RequestDelegate next, IWebHostEnvironment env, ILogger logger) { _next = next; _env = env; _logger = logger; } public async Task Invoke(HttpContext context) { string message = null; var httpStatusCode = HttpStatusCode.InternalServerError; var apiStatusCode = ApiResultStatusCode.ServerError; try { await _next(context); } catch (BaseApiException exception) { _logger.LogError(exception, exception.Message); httpStatusCode = exception.HttpStatusCode; apiStatusCode = exception.ApiStatusCode; if (_env.IsDevelopment()) { var dic = new Dictionary { ["Exception"] = exception.Message, ["StackTrace"] = exception.StackTrace }; if (exception.InnerException != null) { dic.Add("InnerException.Exception", exception.InnerException.Message); dic.Add("InnerException.StackTrace", exception.InnerException.StackTrace); } if (exception.AdditionalData != null) dic.Add("AdditionalData", JsonConvert.SerializeObject(exception.AdditionalData)); var contractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }; message = JsonConvert.SerializeObject(dic, new JsonSerializerSettings { ContractResolver = contractResolver, Formatting = Formatting.Indented }); } else { message = exception.Message; } if(exception.AdditionalData==null) await WriteToResponseAsync(); else await WriteToResponseWithObjectAsync(exception.AdditionalData); } catch (SecurityTokenExpiredException exception) { _logger.LogError(exception, exception.Message); SetUnAuthorizeResponse(exception); await WriteToResponseAsync(); } catch (UnauthorizedAccessException exception) { _logger.LogError(exception, exception.Message); SetUnAuthorizeResponse(exception); await WriteToResponseAsync(); } catch (Exception exception) { _logger.LogError(exception, exception.Message); if (_env.IsDevelopment()) { var dic = new Dictionary { ["Exception"] = exception.Message, ["InnerException"] = exception.InnerException?.Message, ["StackTrace"] = exception.StackTrace }; message = JsonConvert.SerializeObject(dic); } message = exception.Message; await WriteToResponseAsync(); } async Task WriteToResponseAsync() { if (context.Response.HasStarted) throw new InvalidOperationException("The response has already started, the http status code middleware will not be executed."); var result = new ApiResult(false, apiStatusCode, message); var contractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }; var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings { ContractResolver = contractResolver, Formatting = Formatting.Indented }); context.Response.StatusCode = (int)httpStatusCode; context.Response.ContentType = "application/json"; await context.Response.WriteAsync(json); } async Task WriteToResponseWithObjectAsync(object additionalData) { if (context.Response.HasStarted) throw new InvalidOperationException( "The response has already started, the http status code middleware will not be executed."); var result = new ApiResult(false, apiStatusCode, additionalData, message); var contractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }; var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings { ContractResolver = contractResolver, Formatting = Formatting.Indented }); context.Response.StatusCode = (int)httpStatusCode; context.Response.ContentType = "application/json"; await context.Response.WriteAsync(json); } void SetUnAuthorizeResponse(Exception exception) { httpStatusCode = HttpStatusCode.Unauthorized; apiStatusCode = ApiResultStatusCode.UnAuthorized; if (_env.IsDevelopment()) { var dic = new Dictionary { ["Exception"] = exception.Message, ["StackTrace"] = exception.StackTrace }; if (exception is SecurityTokenExpiredException tokenException) dic.Add("Expires", tokenException.Expires.ToString()); message = JsonConvert.SerializeObject(dic); } } JwtSecurityToken ReadJwtToken(bool fromHeader = true) { try { if (fromHeader) { var stream = context.Request.Headers.Values.First(v => v.FirstOrDefault().Contains("Bearer")) .FirstOrDefault(); var handler = new JwtSecurityTokenHandler(); var jsonToken = handler.ReadToken(stream.Split(" ").Last()); return jsonToken as JwtSecurityToken; } else { string stream = context.Request.Query["access_token"]; ; var handler = new JwtSecurityTokenHandler(); var jsonToken = handler.ReadToken(stream.Split(" ").Last()); return jsonToken as JwtSecurityToken; } } catch (Exception e) { throw new BaseApiException(ApiResultStatusCode.UnAuthorized, e.Message + " Jwt is wrong", HttpStatusCode.Unauthorized); } } } }