Я пытаюсь написать пару API и хочу иметь стандартное расположение для обработки любых неперехваченных исключений. Этот обработчик должен сделать две вещи: отформатировать и зарегистрировать исключение, а затем вернуть стандартизированное тело ответа. Мне удалось выполнить ведение журнала, и после исследования я попробовал несколько способов записать свой объект в тело ответа, но независимо от того, вызываю ли я через почтальона или другой API, я никогда не получаю обратно тело ответа. На данный момент мне нужна помощь, чтобы определить, почему я наблюдаю такое поведение и что может быть не так с моими решениями.
Я попробовал 3 разные реализации обработчика исключений. (пользовательское промежуточное программное обеспечение, пользовательский класс IExceptionHandler, прямая запись лямбда-выражения app.UseExceptionHandler) и несколько способов успешной записи в тело. Я изменил ответ.StatusCode и могу вернуть разные, но никогда не получу тело. Я также попытался изменить порядок вызова моего промежуточного программного обеспечения/ExceptionHandler в Program.cs, чтобы определить, могут ли какие-либо дополнительные промежуточные программы впоследствии его модифицировать, что также вернуло тот же результат.
Сначала я выбрал реализацию промежуточного программного обеспечения, которую можно найти ниже, поскольку это был наиболее знакомый мне способ реализации глобальной обработки исключений.
public class ExceptionMiddleware
{
private RequestDelegate _next;
private SecurityHeadersPolicy _policy;
public ExceptionMiddleware(RequestDelegate next, SecurityHeadersPolicy policy)
{
_next = next;
}
public async Task Invoke(HttpContext context, ILogger logger)
{
try
{
await _next(context);
}
catch (Exception ex)
{
logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", ex);
context.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId);
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
var response = new DeveloperMessageResponse()
{
ErrorCode = string.Format("{0:0000}", CommonLogCode.UnhandledError),
ReferenceId = transactionId,
DeveloperMessage = "An unhandled exception occurred.",
DisplayMessage = "An unexpected error occurred."
};
IHeaderDictionary headers = context.Response.Headers;
foreach (var headerValuePair in _policy.SetHeaders)
{
headers[headerValuePair.Key] = headerValuePair.Value;
}
foreach (var header in _policy.RemoveHeaders)
{
headers.Remove(header);
}
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
}
Когда мне это не удалось, я провел дополнительное исследование и обнаружил, что в .Net 8 рекомендуемым подходом является реализация специального IExceptionHandler:
public class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger _logger;
public GlobalExceptionHandler(ILogger logger)
{
_logger = logger;
}
public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
_logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", exception);
httpContext.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId);
httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
httpContext.Response.ContentType = "application/json";
IHeaderDictionary headers = httpContext.Response.Headers;
var response = new DeveloperMessageResponse()
{
ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError),
ReferenceId = transactionId,
DeveloperMessage = "An unhandled exception occurred.",
DisplayMessage = "An unexpected error occurred."
};
await httpContext.Response.WriteAsJsonAsync(JsonSerializer.Serialize(response));
return true;
}
Когда мне не удалось заставить это работать, я попытался использовать лямбда-подход в Program.cs, который является моей текущей реализацией. Я попытался использовать httpContext.Response.WriteAsJsonAsync, httpContext.Response.WriteAsync и httpContext.Response.Body.Write, чтобы попытаться вернуть тело:
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
var logger = app.Services.GetRequiredService();
var policy = securityPolicy.Build();
var exceptionHandlerFeature =
context.Features.Get();
logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", exceptionHandlerFeature?.Error);
context.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId);
//context.Response.Clear();
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.ContentType = "application/json";
IHeaderDictionary headers = context.Response.Headers;
foreach (var headerValuePair in policy.SetHeaders)
{
headers[headerValuePair.Key] = headerValuePair.Value;
}
foreach (var header in policy.RemoveHeaders)
{
headers.Remove(header);
}
var response = new DeveloperMessageResponse()
{
ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError),
ReferenceId = transactionId,
DeveloperMessage = "An unhandled exception occurred.",
DisplayMessage = "An unexpected error occurred."
};
//var responseBuffer = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response));
//await context.Response.Body.WriteAsync(responseBuffer, 0, responseBuffer.Length);
await context.Response.WriteAsJsonAsync(JsonSerializer.Serialize(response));
//await context.Response.CompleteAsync();
});
});
Вот мой файл Program.cs. Здесь есть комментарии, в которых я пытался настроить каждую реализацию, а также текущую реализацию лямбды.
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseKestrel(options => { options.AddServerHeader = false; options.AllowResponseHeaderCompression = false; });
// Add services to the container.
builder.Services.AddMvcCore().AddApiExplorer();
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
builder.Services.Configure(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddHttpContextAccessor();
builder.Services.AddApiAndSwaggerVersioningconfigurations();
builder.Services.AddAutoMapperDependencies("UserAPI*.dll");
builder.Services.AddFrameworkDependencies();
builder.Services.AddApplicationDependencies("UserAPI*.dll");
//builder.Services.AddExceptionHandler();
var app = builder.Build();
var securityPolicy = new SecurityHeadersBuilder().AddDefaultAPISecurePolicy();
//app.UseExceptionMiddleware(securityPolicy);
app.UseForwardedHeaders();
//app.UseExceptionHandler(opt => { });
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
var logger = app.Services.GetRequiredService();
var policy = securityPolicy.Build();
var exceptionHandlerFeature =
context.Features.Get();
logger.LogError((int)CommonLogCode.UnhandledError, "An unhandled error occurred.", exceptionHandlerFeature?.Error);
context.Request.Headers.TryGetValue(HeaderConstants.TransactionIdKey, out var transactionId);
//context.Response.Clear();
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.ContentType = "application/json";
IHeaderDictionary headers = context.Response.Headers;
foreach (var headerValuePair in policy.SetHeaders)
{
headers[headerValuePair.Key] = headerValuePair.Value;
}
foreach (var header in policy.RemoveHeaders)
{
headers.Remove(header);
}
var response = new DeveloperMessageResponse()
{
ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError),
ReferenceId = transactionId,
DeveloperMessage = "An unhandled exception occurred.",
DisplayMessage = "An unexpected error occurred."
};
//var responseBuffer = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(response));
//await context.Response.Body.WriteAsync(responseBuffer, 0, responseBuffer.Length);
await context.Response.WriteAsJsonAsync(JsonSerializer.Serialize(response));
//await context.Response.CompleteAsync();
});
});
app.UseResponseSecurityHeaderMiddleware(securityPolicy);
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
app.UseHsts();
}
app.UseHttpMiddleware();
app.UsePerformanceTrackingMiddleware();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
int suppressVersionsBelow = 0;
int.TryParse(builder.Configuration[ConfigConstants.SuppressVersionsBelow], out suppressVersionsBelow);
var versioningProvider = app.Services.GetRequiredService();
app.ConfigureSwaggerUI(versioningProvider, suppressVersionsBelow);
app.MapControllers();
app.Run();
Я также пытался настроить и использовать разные хосты (пустельга, IIS, Docker), чтобы определить, могут ли они изменять ответ, но это также не имело значения.< /p>
Заголовки запросов Postman и тело/статус ответа
Я ожидаю, что тело будет json-версией этого объекта, но в настоящее время оно пусто:
п>
{
ErrorCode = string.Format("{0:0000}", (int)CommonLogCode.UnhandledError),
ReferenceId = transactionId,
DeveloperMessage = "An unhandled exception occurred.",
DisplayMessage = "An unexpected error occurred."
}
Подробнее здесь: https://stackoverflow.com/questions/783 ... ponse-body
Глобальный обработчик исключений .Net 8 не пишет ответ. Тело ⇐ C#
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Обработчик исключений Spring @Controller и глобальный обработчик исключений. Как вызвать оба
Anonymous » » в форуме JAVA - 0 Ответы
- 10 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Глобальный обработчик исключений отменяет обработчик транзакций базы данных
Anonymous » » в форуме JAVA - 0 Ответы
- 16 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Глобальный обработчик ошибок для приложений React Native (android, ios)
Anonymous » » в форуме Android - 0 Ответы
- 17 Просмотры
-
Последнее сообщение Anonymous
-