自定义错误响应不正确的json,Dotnet Core Web API

gstyhher  于 2023-05-30  发布在  其他
关注(0)|答案(4)|浏览(172)

如果在Dotnet Core中为WebApi提供了无效的类型,是否有一种返回自定义错误响应的机制?
例如
如果我有一个像这样的类

public class SomeApiClass
{
    public int Id { get; set; }
}

但是像这样发出一个post请求(注意,我期望一个int并给出一个字符串):

{
    "id": "f"
}

然后标准的dotnet响应看起来像这样:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-27be45d9cffab14698524a63120a4f88-6bfe2613f2328a42-00",
    "errors": {
        "$.id": [
            "The JSON value could not be converted to System.Int64. Path: $.wmdaid | LineNumber: 1 | BytePositionInLine: 15."
        ]
    }
}

但是,我希望我的所有响应对于错误请求看起来都是一样的,这样任何实现API的人都可以得到一致的JSON。我的问题是JSON反序列化是在控制器验证之前完成的。
那么,简而言之,是否可以将此响应格式作为dotnet中间件的一部分进行更改?

nc1teljy

nc1teljy1#

您可以使用自定义ActionFilter

public class ReformatValidationProblemAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is BadRequestObjectResult badRequestObjectResult)
            if (badRequestObjectResult.Value is ValidationProblemDetails)
            {
                context.Result = new BadRequestObjectResult("Custom Result Here");
            }

        base.OnResultExecuting(context);
    }
}

Controller.cs

[ApiController]
[ReformatValidationProblem]
public class Controller : ControllerBase
{ 
    ...
}

或全局注册Startup.cs

services.AddMvc(options =>
{
    options.Filters.Add(typeof(ReformatValidationProblemAttribute));
});
xwbd5t1u

xwbd5t1u2#

您还可以配置JsonOptions,以便显示通用消息。

builder.Services.AddControllers().AddJsonOptions(o => o.AllowInputFormatterExceptionMessages = false);

这将保留自动400响应(来自ValidationProblem)中的所有其他字段,并显示格式错误字段的一般错误消息:“输入无效。”

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-190787f7ecae2a19b0e9c5da9c270fad-42237ddd1f920665-00",
    "errors": {
        "$.id": [
            "The input was not valid."
        ]
    }
}
ss2ws0br

ss2ws0br3#

您可以实现自定义错误模型处理程序,并在每个场景中(例如错误请求或...)将其替换为默认ModelState对象。首先,更改服务提供程序以注入您的自定义错误类,如下所示:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)    
  .ConfigureApiBehaviorOptions(options => {      
   options.InvalidModelStateResponseFactory = actionCtx => {  
    return CustomBadRequestHandler(actionCtx);  
   };  
  });

接下来,我们将创建自定义的错误处理程序类:

private BadRequestObjectResult CustomBadRequestHandler(ActionContext actionCtx) {      
 return new BadRequestObjectResult(actionCtx.ModelState  
  .Where(modelError => modelError.Value.Errors.Count > 0)  
  .Select(modelError => new Error {  
   ErrorFieldKey = modelError.Key,  
    ErrorDescription = modelError.Value.Errors.FirstOrDefault().ErrorMessage  
  }).ToList());  
}

最后,我们想要返回的自定义错误模型:

public class Error    
{    
    //your custom filed that you want to show
    public string ErrorFieldKey { get; set; }    
    public string ErrorDescription { get; set; }         
}
ddarikpa

ddarikpa4#

.NET 6.0

您可以执行以下操作:
1.创建自定义验证属性:PositiveInt32ValidationAttribute.cs
1.创建自定义结果过滤器:MyApiResultFilter.cs
1.在Program.cs中注册此结果筛选器。
下面是一个示例:

PositiveInt32ValidationAttribute.cs

public class PositiveInt32ValidationAttribute : ValidationAttribute
{
    protected override ValidationResult? IsValid(Object? value, ValidationContext validationContext)
    {
        var memberNames = new List<String> { validationContext.MemberName! };
        var errorMessage = String.Format("Invalid {0}.", validationContext.MemberName);
        if (value is Int32 id && id > 1)
            return ValidationResult.Success;
        return new ValidationResult(errorMessage, memberNames);
    }
}

MyApiResultFilter.cs

public class MyApiResultFilter : IResultFilter
{
    public void OnResultExecuted(ResultExecutedContext context)
    {

    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            var count = context.ModelState.Count;
            var errors = new Dictionary<String, String[]>(count);
            foreach (var keyModelStatePair in context.ModelState)
            {
                var key = keyModelStatePair.Key;
                var modelErrors = keyModelStatePair.Value.Errors;
                if (modelErrors is not null && modelErrors.Count > 0)
                {
                    var errorMessages = modelErrors.Select(error => error.ErrorMessage).ToArray();
                    errors.Add(key, errorMessages);
                }
            }

            var response = new
            {
                StatusCode = StatusCodes.Status400BadRequest,    //namespace Microsoft.AspNetCore.Http
                IsSuccess = false,
                Result = errors
            };
            context.Result = new BadRequestObjectResult(response);
        }
    }
}

在Program.cs中注册MyApiResultFilter

var builder = WebApplication.CreateBuilder(args);
builder.Services
    .AddControllers(config => config.Filters.Add(new MyApiResultFilter())
    .AddNewtonsoftJson(options =>    //I am using it to get the response in snake_case JSON format. You don't have to do this.
    {
        options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
        options.SerializerSettings.ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() };
    });

结果

{
    "status_code": 400,
    "is_success": false,
    "result": {
        "id": [
            "Invalid id."
        ]
    }
}

截图

相关问题