繁体   English   中英

.Net Core Api 无法访问 model 验证失败的原始值

[英].Net Core Api cannot access original value on model validation failures

我无法访问未通过 model 验证的原始值。 我怀疑ModelStateEntry中的AttemptedValue和/或RawValue包含原始值,但是这两个属性都是null

为了澄清,我写了一个简约的 api 来展示这个问题。

model 验证:

public class User
{
    [EmailAddress]
    public string Email { get; set; }
}

controller:

[ApiController]
[Route("test")]
public class TestController : ControllerBase
{
    [HttpPost]
    [ValidationFilter()]
    public string Test([FromBody] User user)
    {
        return user.Email;
    }
}

验证过滤器:

public class ValidationFilterAttribute : ActionFilterAttribute, IOrderedFilter
{
    public int Order { get; } = int.MinValue;

    override public void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            ModelStateEntry entry = context.ModelState.ElementAt(0).Value;
            var attemptedVal = entry.AttemptedValue;
            var rawVal = entry.RawValue;
            context.Result = new OkObjectResult(rawVal);
        }
    }
}

当我用这个 model 调用测试方法时:

{
    "email": "No email here ;)"
}

ValidationFilterAttribute 代码按预期调用,但ModelStateEntry不包含原始值。 AttemptedValueRawValue都是null

Visual Studio 调试屏幕截图

据我所知,对于 model 绑定,过滤器将调用 context.ModelState.SetModelValue 来设置 RawValue 和 AttemptedValue 的值。

但是 SystemTextJsonInputFormatter 并没有设置它来解决这个问题,我建议你可以尝试构建自定义扩展方法并重试。

更多细节,您可以参考以下代码:

创建一个新的 ModelStateJsonInputFormatter class:

public class ModelStateJsonInputFormatter : SystemTextJsonInputFormatter
{
    public ModelStateJsonInputFormatter(ILogger<ModelStateJsonInputFormatter> logger, JsonOptions options) : 
        base(options ,logger)
    {
    }
    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        var result = await base.ReadRequestBodyAsync(context);
        foreach (var property in context.ModelType.GetProperties())
        {
            var propValue = property.GetValue(result.Model, null);
            var propAttemptValue = property.GetValue(result.Model, null)?.ToString();
            context.ModelState.SetModelValue(property.Name, propValue, propAttemptValue);
        }
        return result;
    }
}

在 startup.cs 中重新注册它:

            services.AddControllersWithViews(options => {
                var serviceProvider = services.BuildServiceProvider();
                var modelStateJsonInputFormatter = new ModelStateJsonInputFormatter(
            serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger<ModelStateJsonInputFormatter>(),
serviceProvider.GetRequiredService<IOptions<JsonOptions>>().Value);
                options.InputFormatters.Insert(0, modelStateJsonInputFormatter);
                });

结果:

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM