using System; using System.Collections.Generic; using System.Net; using System.Text; using System.Threading.Tasks; using iPackage.Models.Api; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; namespace iPackage.Core.Web.WebFramework.Middlewares { public static class ExceptionHandlerMiddlewareExtensions { public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder) { return applicationBuilder.UseMiddleware(); } } public class ExceptionHandlerMiddleware { private readonly RequestDelegate _next; private readonly IHostingEnvironment _env; private readonly ILogger _logger; public ExceptionHandlerMiddleware(RequestDelegate next, IHostingEnvironment env, ILogger logger) { _next = next; _env = env; _logger = logger; } public async Task Invoke(HttpContext context) { string message = null; HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError; ApiResultStatusCode apiStatusCode = ApiResultStatusCode.ServerError; try { await _next(context); } catch (AppException 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)); message = JsonConvert.SerializeObject(dic); } else { message = exception.Message; } await WriteToResponseAsync(); } 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); } 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 json = JsonConvert.SerializeObject(result); 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); } } } } }