Пользовательский обработчик исключений в API Controller сбой в C# и .NET 8C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Пользовательский обработчик исключений в API Controller сбой в C# и .NET 8

Сообщение Anonymous »

В настоящее время я узнаю об управлении ошибками в управлении ошибками в проектах ASP.NET Core Web API, чтобы попытаться найти элегантное решение, которое гарантирует, что проблемы с проблемами всегда возвращается, когда что -то идет не так.
Я использую шаблон API WeachforeCast < /code>, который создается при создании нового проекта C# /ASP.NET Core 8 с контроллерами. < /p>
У меня есть реализовал пользовательский обработчик исключений; Однако я обнаружил, что это не всегда работает. , код статуса и информация заголовка; Однако, когда я вызываю API из функции «Попробуйте это» в интерфейсе Swagger , я возвращаю неправильный код состояния (внутренняя ошибка 500) с деталями исключения, а не с проблемами с проблемами и неправильно Информация заголовка. /code> Метод возвращает false Если я пробую код из Swagger; Однако, когда я выполняю тот же код, вызывая его из Postman the argendetailsservice.trywriteasync (...) Метод возвращает true .
Я поместил случай Ибо, когда «woodgedetailsservice.triteasync (...)» возвращает, что я мог бы попытаться напрямую написать проблему, что дает задачу httpcontext.response .
Когда я это сделал, я смог поймать следующее исключение (опять же, это происходит только при использовании функции кода Swagger's Try .... не при вызове из почтальона): < /p>


< P> сериализация и десериализация экземпляров 'System.Type' не поддерживается. Путь: $ .httpcontext.features.key. "< /P>
< /blockquote>
Я не знаю, почему это терпит неудачу. < /P>
Я ищу помощь в том, как обеспечить ведение моего управления ошибками так же, независимо от того, как называется API. /p>
public class GlobalExceptionHandler : IExceptionHandler
{
private readonly IProblemDetailsService _problemDetailsService;

public GlobalExceptionHandler(IProblemDetailsService problemDetailsService)
{
if (problemDetailsService == null) throw new ArgumentException(nameof(problemDetailsService));
_problemDetailsService = problemDetailsService;
}

public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
var message = exception switch
{
ArgumentException => ((ArgumentException)exception).Message,
ValidationException => ((ValidationException)exception).Message,
_ => $"Internal Server Error ({exception.GetType().Name})"
};

int status = exception switch
{
ArgumentException => (int)HttpStatusCode.BadRequest,
ValidationException => (int)HttpStatusCode.BadRequest,
_ => (int)HttpStatusCode.InternalServerError
};

ProblemDetails problemDetails = new()
{
Title = $"Bad Request: {exception.GetType().Name}", // human-readable summary of the problem type
Detail = message, //detailed explanation specific to the problem
Status = status,
Instance = httpContext.Request.GetEncodedUrl(),
Type = exception.HelpLink
};

var errorcontext = new ProblemDetailsContext()
{
HttpContext = httpContext,
ProblemDetails = problemDetails,
//Exception = exception,
AdditionalMetadata = null
};

httpContext.Response.Clear();
httpContext.Response.StatusCode = status;

var written = await _problemDetailsService.TryWriteAsync(errorcontext);

if (!written)
{
try
{
await httpContext.Response.WriteAsJsonAsync(errorcontext);
written = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
written = false;
}
}

return written;
}
}

Это моя программа.cs :
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net;
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Net.Http;
using Microsoft.AspNetCore.Diagnostics;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressMapClientErrors = false;
options.SuppressInferBindingSourcesForParameters = false;
options.SuppressModelStateInvalidFilter = false;

options.ClientErrorMapping[StatusCodes.Status404NotFound].Title = "The item you were looking for could not be found";
options.ClientErrorMapping[StatusCodes.Status400BadRequest].Title = "Please correct the problem...bad request";

options.InvalidModelStateResponseFactory = context =>
{

//This handles the cases where the model state does not validate
//it logs the problem as a warning and returns a problem details with the invalid details
var logger = context.HttpContext.RequestServices
.GetRequiredService();

// Perform logging of original error.
var message = string.Join(" \n ", context.ModelState.Values
.SelectMany(v => v.Errors)
.Select(e => e.ErrorMessage));

logger.LogWarning(message);
Dictionary errors = new Dictionary();

if (context.ModelState != null)
{
foreach (var k in context.ModelState.Keys)
{
var errorMessages = context.ModelState[k];

if (errorMessages != null)
{
List messages = new List();

foreach (var entry in errorMessages.Errors)
{
messages.Add(entry.ErrorMessage.ToString());
}

errors.Add(k, messages.ToArray());
}
}
}

ValidationException validationException = new ValidationException();

// Invoking a custom response by returning a generic error message implementation of IActionResult instead of the default
var genericErrorDictionary = new Dictionary();
genericErrorDictionary.Add("", new string[] { "Unable to process the request.", message });

return new Microsoft.AspNetCore.Mvc.BadRequestObjectResult(new Microsoft.AspNetCore.Mvc.ValidationProblemDetails()
{
Title = $"Bad Request: please correct validation errors.", // human-readable summary of the problem type
Detail = message, //detailed explanation specific to the problem
Status = (int)HttpStatusCode.BadRequest,//status code
Instance = context.HttpContext.Request.GetEncodedUrl(),//URL to the instance that had the problem
Type = validationException.HelpLink, //help for validation errors
Errors = errors //the validation errors
});
};
});

// Add services to the container.
builder.Services.AddExceptionHandler(); // Using a custom exception handler that converts the exception into a Problem Details
builder.Services.AddProblemDetails(); // required for using the exception handler with the custom problem details exception handler code because it adds the services required for Problem Details

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseExceptionHandler(opt => { }); //adding the custom GlobalExceptionHandler to the app's pipeline

// The following also fails to write the problem details to the response
//app.UseExceptionHandler(opt =>
//{
// opt.Run(async httpContext =>
// {
// var exceptionHandlerPathFeature = httpContext.Features.Get();
// var exception = exceptionHandlerPathFeature.Error;
// var message = exception switch
// {
// ArgumentException => ((ArgumentException)exception).Message,
// ValidationException => ((ValidationException)exception).Message,
// _ => $"Internal Server Error ({exception.GetType().Name})"

// };

// int status = exception switch
// {
// ArgumentException => (int)HttpStatusCode.BadRequest,
// ValidationException => (int)HttpStatusCode.BadRequest,
// _ => (int)HttpStatusCode.InternalServerError

// };
// ProblemDetails problemDetails = new()
// {
// Title = $"Bad Request: {exception.GetType().Name}", // human-readable summary of the problem type
// Detail = message, //detailed explanation specific to the problem
// Status = status,
// Instance = httpContext.Request.GetEncodedUrl(),
// Type = exception.HelpLink
// };

// var errorcontext = new ProblemDetailsContext()
// {
// HttpContext = httpContext,
// ProblemDetails = problemDetails,
// //Exception = exception,
// AdditionalMetadata = null
// };
// httpContext.Response.Clear();
// httpContext.Response.StatusCode = status;
// await httpContext.Response.WriteAsJsonAsync(errorcontext);
// });
//}); //adding the custom GlobalExceptionHandler to the app's pipleline

app.UseAuthorization();

app.MapControllers();

app.Run();

И это реализация для моей WeatherForeCastController (обратите внимание, что я передаю значение 1 методу Get , чтобы заставить его бросить ArgeryException )
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

private readonly ILogger _logger;

public WeatherForecastController(ILogger logger)
{
_logger = logger;
}

[HttpGet("GetWeatherForecast")]
public ActionResult GetWeatherForecast(int weekDay)
{
if (weekDay < 0 || weekDay > 6)
throw new System.ComponentModel.DataAnnotations.ValidationException("Please provide a valid value for a week day: between 0 and 6");

if (weekDay == 1)
{
ModelState.AddModelError("weekDay", "Please provide a valid value for a week day: between 0 and 6");
// return BadRequest(new ProblemDetails() { Detail = "Please provide a valid value for a week day: between 0 and 6" });
// return BadRequest(ValidationProblem("Please provide a valid value for a week day: between 0 and 6", modelStateDictionary: ModelState));
// return BadRequest();
throw new ArgumentException("Please provide a valid value for a week day: between 0 and 6");
//return BadRequest("Please provide a valid value for a week day: between 0 and 6");
}

return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}

[HttpPost("GetWeatherForecastDTO")]
public ActionResult GetWeatherForecastDTO(WeatherForecastRequest request)
{
var weekDay = request.DayOfWeek;

if (weekDay == 1)
throw new Exception("Bad range: please provide a valid value for the week day between 0 and 6");

//throw new ArgumentOutOfRangeException("request", "Bad range: please provide a valid value for the week day between 0 and 6");
// return BadRequest();
//throw new ArgumentException("Please provide a valid value for a week day: between 0 and 6");
//return BadRequest("Please provide a valid value for a week day: between 0 and 6");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
< /code>
С моделью передачи данных по умолчанию (которую я никогда не использую, потому что я сосредоточен на обработке ошибок): < /p>
public class WeatherForecast
{
public DateOnly Date { get; set; }

public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

public string? Summary { get; set; }
}

public class WeatherForecastRequest
{
[System.ComponentModel.DataAnnotations.Range(0, 6, ErrorMessage = "Please provide a valid value for a week day: between 0 and 6 (data annotation)")]
public int DayOfWeek { get; set; }
}


Подробнее здесь: https://stackoverflow.com/questions/794 ... -and-net-8
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»