156 lines
5.7 KiB
C#
156 lines
5.7 KiB
C#
using Microsoft.AspNetCore.Http;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
|
||
namespace Kit.Helpers;
|
||
|
||
public enum StackTraceModesJson
|
||
{
|
||
None = 0,
|
||
Text = 1,
|
||
Html = 2
|
||
}
|
||
|
||
public enum StackTraceModesHtml
|
||
{
|
||
None = 0,
|
||
Text = 1,
|
||
Html = 2,
|
||
|
||
CommentText = 3,
|
||
CommentHtml = 4,
|
||
}
|
||
|
||
public interface IConfigurationExceptionHandler
|
||
{
|
||
StackTraceModesJson StackTraceModeJson { get; }
|
||
StackTraceModesHtml StackTraceModeHtml { get; }
|
||
}
|
||
|
||
public class ConfigurationExceptionHandler : IConfigurationExceptionHandler
|
||
{
|
||
public StackTraceModesJson StackTraceModeJson { get; private set; }
|
||
public StackTraceModesHtml StackTraceModeHtml { get; private set; }
|
||
|
||
public ConfigurationExceptionHandler(Microsoft.Extensions.Configuration.IConfiguration configuration)
|
||
{
|
||
var helper = new ConfigurationHelper(configuration, "ExceptionHandler");
|
||
StackTraceModeJson = helper.GetAppSettingValue("StackTraceModeJson", required: false, defaultValue: StackTraceModesJson.None.ToString()).ParseToEnum<StackTraceModesJson>();
|
||
StackTraceModeHtml = helper.GetAppSettingValue("StackTraceModeHtml", required: false, defaultValue: StackTraceModesHtml.None.ToString()).ParseToEnum<StackTraceModesHtml>();
|
||
}
|
||
}
|
||
|
||
public static class ExceptionHandlerMiddlewareExt
|
||
{
|
||
public static IServiceCollection InitExceptionHandlerMiddleware(this IServiceCollection builder, IConfigurationExceptionHandler configuration)
|
||
{
|
||
ExceptionHandlerMiddleware.Init(configuration);
|
||
return builder;
|
||
}
|
||
}
|
||
|
||
public class ExceptionHandlerMiddleware
|
||
{
|
||
private static IConfigurationExceptionHandler? _exceptionHandler;
|
||
private static StackTraceModesJson _stackTraceModeJson => _exceptionHandler?.StackTraceModeJson ?? StackTraceModesJson.None;
|
||
private static StackTraceModesHtml _stackTraceModeHtml => _exceptionHandler?.StackTraceModeHtml ?? StackTraceModesHtml.None;
|
||
|
||
private readonly RequestDelegate _next;
|
||
|
||
public static void Init(IConfigurationExceptionHandler exceptionHandler)
|
||
{
|
||
_exceptionHandler = exceptionHandler;
|
||
}
|
||
|
||
public ExceptionHandlerMiddleware(RequestDelegate next)
|
||
{
|
||
_next = next;
|
||
}
|
||
|
||
public async Task Invoke(HttpContext context)
|
||
{
|
||
try
|
||
{
|
||
await _next(context);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
int statusCode = 0;
|
||
string errorMessage = string.Empty;
|
||
string errorStackTrace = string.Empty;
|
||
string? redirectUrl = null;
|
||
bool forceJson = false;
|
||
|
||
switch (ex)
|
||
{
|
||
case AuthenticationException exception:
|
||
statusCode = StatusCodes.Status401Unauthorized;
|
||
errorMessage = exception.Message;
|
||
redirectUrl = exception.RedirectUrl;
|
||
forceJson = true;
|
||
break;
|
||
|
||
case AuthorizationException exception:
|
||
statusCode = StatusCodes.Status403Forbidden;
|
||
errorMessage = exception.Message;
|
||
redirectUrl = exception.RedirectUrl;
|
||
forceJson = true;
|
||
break;
|
||
|
||
case InvalidOperationException exception:
|
||
statusCode = StatusCodes.Status409Conflict;
|
||
errorMessage = exception.Message;
|
||
break;
|
||
default:
|
||
statusCode = StatusCodes.Status500InternalServerError;
|
||
errorMessage = "На сервере произошла неизвестная ошибка" + Environment.NewLine + ex.Message;
|
||
break;
|
||
}
|
||
|
||
context.Response.StatusCode = statusCode;
|
||
|
||
if (forceJson || context.NeedResponseJsonResult(ex))
|
||
{
|
||
switch (_stackTraceModeJson)
|
||
{
|
||
case StackTraceModesJson.Text:
|
||
errorStackTrace = ex?.GetInfoAsPlainText() ?? string.Empty;
|
||
break;
|
||
case StackTraceModesJson.Html:
|
||
errorStackTrace = ex?.GetInfoAsHtml() ?? string.Empty;
|
||
break;
|
||
}
|
||
|
||
string json = new JsonResultError
|
||
{
|
||
ErrorMessage = errorMessage,
|
||
ErrorStackTrace = errorStackTrace,
|
||
RedirectUrl = redirectUrl
|
||
}.JsonSerialize(enableCyrillic: true, propertyNamingPolicy: System.Text.Json.JsonNamingPolicy.CamelCase);
|
||
context.Response.ContentType = "application/json; charset=utf-8";
|
||
await context.Response.WriteAsync(json, System.Text.Encoding.UTF8);
|
||
}
|
||
else
|
||
{
|
||
switch (_stackTraceModeHtml)
|
||
{
|
||
case StackTraceModesHtml.Text:
|
||
errorStackTrace = ex.GetInfoAsPlainText() ?? string.Empty;
|
||
break;
|
||
case StackTraceModesHtml.Html:
|
||
errorStackTrace = ex.GetInfoAsHtml() ?? string.Empty;
|
||
break;
|
||
case StackTraceModesHtml.CommentText:
|
||
errorStackTrace = "<!-- " + ex.GetInfoAsPlainText() ?? string.Empty + " -->";
|
||
break;
|
||
case StackTraceModesHtml.CommentHtml:
|
||
errorStackTrace = "<!-- " + ex.GetInfoAsHtml() ?? string.Empty + " -->";
|
||
break;
|
||
}
|
||
|
||
errorMessage += Environment.NewLine + errorStackTrace;
|
||
context.Response.ContentType = "text/html; charset=utf-8";
|
||
await context.Response.WriteAsync(errorMessage, System.Text.Encoding.UTF8);
|
||
}
|
||
}
|
||
}
|
||
} |