Api/NetinaShop.Api/WebFramework/MiddleWares/ExceptionHandlerMiddleware.cs

207 lines
7.2 KiB
C#

namespace NetinaShop.Api.WebFramework.MiddleWares;
public static class ExceptionHandlerMiddlewareExtensions
{
public static IApplicationBuilder UseExceptionHandlerMiddleware(this IApplicationBuilder applicationBuilder)
{
return applicationBuilder.UseMiddleware<ExceptionHandlerMiddleware>();
}
}
public class ExceptionHandlerMiddleware
{
private readonly IWebHostEnvironment _env;
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
private readonly RequestDelegate _next;
public ExceptionHandlerMiddleware(
RequestDelegate next,
IWebHostEnvironment env,
ILogger<ExceptionHandlerMiddleware> 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<string, string>
{
["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<string, string>
{
["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<object>(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<string, string>
{
["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);
}
}
}
}