Fluent 验证自定义响应 ASP.NET Core Web API

Fluent validation custom response ASP.NET Core Web API

我正在研究 ASP.NET Core 6 Web API 项目。我们使用 Fluent Validation。我如何 return 自定义响应。请指教

我想针对页面、限制、日期等不同的验证错误发送自定义响应

这是我默认得到的响应:

  {
       "type": "",
       "title": "One or more validation errors occurred.",
       "status": 400,
       "traceId": "00-097c689850af328c49705cea77fc6fbd-0c7defe165d9693f-00",
       "errors": {
         "Page": [
           "Page value should be greater than 0"
         ],
         "Limit": [
           "Limit value should be greater than 0"
         ]
       }
}

这是我想要得到的回复:

{
  "traceId": "e45b3398-a2a5-43eb-8851-e45de1184021",
  "timestamp": "2021-06-28T00:32:06.548Z",
  "errors": [
    {
      "errorCode": "Contract Violation",
      "message": "Page should be greater than 0",
      "priority": "MEDIUM",
      "properties": {
        "name": "string",
        "value": "string"
      }
    }
  ]
}

这是我的代码:

public async Task<IActionResult> Get([FromQuery] DataParameter input) 
{

}

public class DataParameter 
{
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public int Page { get; set; }
    public int Limit { get; set; }
}

public class QueryParameterValidator : AbstractValidator<QueryParameter>
{
    public QueryParameterValidator()
    {
        RuleFor(model => model.Page)
            .GreaterThan(0)
            .WithMessage("Page value should be greater than 0");
        RuleFor(model => model.Limit)
            .GreaterThan(0)
            .WithMessage("Limit value should be greater than 0");
    
        RuleFor(model => model.StartDate)
            .Matches(@"^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$")
            .WithMessage("Transaction from date should be in the pattern of YYYY-MM-DD");
        RuleFor(model => model.EndDate)
            .Matches(@"^\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])$")
            .WithMessage("Transaction to date should be in the pattern of YYYY-MM-DD");
    }
}

这是您可以遵循的完整工作演示:

型号:

public class ErrorDetail
{
    public string traceId { get; set; }
    public DateTime timestamp { get; set; }
    public List<Error> errors { get; set; } = new List<Error>();
}

public class Error
{
    public string errorCode { get; set; }
    public string message { get; set; }
    public string priority { get; set; }
    public Properties properties { get; set; }=new Properties();
}

public class Properties
{
    public string name { get; set; }
    public string value { get; set; }
}

静态class:

public static class CustomProblemDetails
{
    public static ErrorDetail ErrorDetail { get; set; } =new ErrorDetail();
    public static IActionResult MakeValidationResponse(ActionContext context)
    {
        var problemDetails = new ValidationProblemDetails(context.ModelState)
        {
            Status = StatusCodes.Status400BadRequest,
        };
        foreach (var keyModelStatePair in context.ModelState)
        {
            var errors = keyModelStatePair.Value.Errors;
            if (errors != null && errors.Count > 0)
            {
                if (errors.Count == 1)
                {
                    var errorMessage = GetErrorMessage(errors[0]);
                    ErrorDetail.errors.Add(new Error()
                    {
                        errorCode= "Contract Violation",
                        message = errorMessage,
                        priority= "MEDIUM",
                        properties= new Properties() { 
                            name = "string", 
                            value = "string" 
                        }
                    });
                }
                else
                {
                    var errorMessages = new string[errors.Count];
                    for (var i = 0; i < errors.Count; i++)
                    {
                        errorMessages[i] = GetErrorMessage(errors[i]);
                        ErrorDetail.errors.Add(new Error()
                        {
                            errorCode = "Contract Violation",
                            message = errorMessages[i],
                            priority = "MEDIUM"
                        });
                    }
                }
            }
        }
        ErrorDetail.traceId = context.HttpContext.TraceIdentifier;
        ErrorDetail.timestamp = DateTime.Now;

        var result = new BadRequestObjectResult(ErrorDetail);

        result.ContentTypes.Add("application/problem+json");

        return result;
    }
    static string GetErrorMessage(ModelError error)
    {
        return string.IsNullOrEmpty(error.ErrorMessage) ?
        "The input was not valid." :
        error.ErrorMessage;
    }
}

注册:

builder.Services.AddControllers().AddFluentValidation().ConfigureApiBehaviorOptions(options =>
{
    options.InvalidModelStateResponseFactory = CustomProblemDetails.MakeValidationResponse;
}); 

结果: