Есть ли какой-либо способ добавить код ошибки в ошибку ModelState

#c# #asp.net-core #modelstate #model-validation

#c# #asp.net-core #modelstate #проверка модели

Вопрос:

Я ищу способ добавить код ошибки вместе с сообщением об ошибке в ModelState . например

 ModelState.AddModelError("ErrorKey", new { Code = 4001, Message = "Some error message" });
  

Для некоторых плохих запросов клиент должен выполнить действие, и сравнение сообщения об ошибке не является идеальным решением для принятия решения. ModelState.AddModelError метод принимает только два параметра, ключ ошибки и сообщение. Есть ли способ добиться этого или чего-то подобного?

Ответ №1:

Нет, в вашем коде нет способа достичь того, что вы ищете, когда вы пытаетесь сделать что-то подобное:

 return BadRequest(ModelState); 
  

Вы получите 400 bad request ответ с сообщением, которое вы уже добавили (как вы можете видеть, код ошибки уже был представлен здесь). Итак, в вашем случае нет ни использования, ни способа добавления кода ошибки.

Ответ №2:

Я нашел способ добавить код ошибки в ValidationProblemDetails :

 
public class CustomValidationProblemDetails : ValidationProblemDetails
{
    public CustomValidationProblemDetails()
    {
    }

    [JsonPropertyName("errors")]
    public new IEnumerable<ValidationError> Errors { get; } = new List<ValidationError>();
}
  

ValidationProblemDetails имеет свойство Error, которое есть IDictionary<string, string[]> , и замените это свойство нашей версией, чтобы добавить ошибку кода.

 public class ValidationError
{
    public int Code { get; set; }

    public string Message { get; set; }
}
  

Конструктор ValidationProblemDetails принимает ModelStateDictionary и должен преобразовать его в список ValidationError :

 public CustomValidationProblemDetails(IEnumerable<ValidationError> errors)
{
    Errors = errors;
}

public CustomValidationProblemDetails(ModelStateDictionary modelState)
{
    Errors = ConvertModelStateErrorsToValidationErrors(modelState);
}

private List<ValidationError> ConvertModelStateErrorsToValidationErrors(ModelStateDictionary modelStateDictionary)
{
    List<ValidationError> validationErrors = new();

    foreach (var keyModelStatePair in modelStateDictionary)
    {
        var errors = keyModelStatePair.Value.Errors;
        switch (errors.Count)
        {
            case 0:
                continue;

            case 1:
                validationErrors.Add(new ValidationError { Code = 100, Message = errors[0].ErrorMessage });
                break;

            default:
                var errorMessage = string.Join(Environment.NewLine, errors.Select(e => e.ErrorMessage));
                validationErrors.Add(new ValidationError { Message = errorMessage });
                break;
        }
    }

    return validationErrors;
}
  

Создайте пользовательский ProblemDetailsFactory для создания пользовательских validationproblemdetails, когда мы хотим вернуть неверный ответ на запрос:

 public class CustomProblemDetailsFactory : ProblemDetailsFactory
{
    public override ProblemDetails CreateProblemDetails(HttpContext httpContext, int? statusCode = null, string title = null,
        string type = null, string detail = null, string instance = null)
    {
        var problemDetails = new ProblemDetails
        {
            Status = statusCode,
            Title = title,
            Type = type,
            Detail = detail,
            Instance = instance,
        };

        return problemDetails;
    }

    public override ValidationProblemDetails CreateValidationProblemDetails(HttpContext httpContext,
        ModelStateDictionary modelStateDictionary, int? statusCode = null, string title = null, string type = null,
        string detail = null, string instance = null)
    {
        statusCode ??= 400;
        type ??= "https://tools.ietf.org/html/rfc7231#section-6.5.1";
        instance ??= httpContext.Request.Path;

        var problemDetails = new CustomValidationProblemDetails(modelStateDictionary)
        {
            Status = statusCode,
            Type = type,
            Instance = instance
        };

        if (title != null)
        {
            // For validation problem details, don't overwrite the default title with null.
            problemDetails.Title = title;
        }

        var traceId = Activity.Current?.Id ?? httpContext?.TraceIdentifier;
        if (traceId != null)
        {
            problemDetails.Extensions["traceId"] = traceId;
        }

        return problemDetails;
    }
}
  

И в конце зарегистрировать фабрику:

 public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddTransient<ProblemDetailsFactory, CustomProblemDetailsFactory>();
}
  

Прочитайте Расширяющиеся ProblemDetails — Добавьте код ошибки в ValidationProblemDetails для получения более подробной информации.