为什么.NET Core的模型验证器向我显示模型属性的名称,而不是在验证消息上显示JSON字段名称?

Aleksej_Shherbak

我有以下模型:

public class MyModel
{
     [JsonProperty("screen_width")]
     [Required(ErrorMessage = "Required width")]
     public string ScreenWidth { get; set; }  
}

并在我的控制器中进行验证:

public class MyController
{
    [Route("/api/v1.0/test")]
    [HttpPatch]
    public async Task<IActionResult> SomeAction([FromBody] MyModel viewModel)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    }
}

预期的JSON正文为:

{
    "screen_width": "1900"
}

但是我将通过例如:

{
    "hello": "azazazazazaa!"   
}

那么,我将看到什么作为回应?以下:

在此处输入图片说明

但这是奇怪的行为!我的客户不知道ScreenWidth这是我班的财产。为什么客户必须知道这一点?他们只知道screen_width

因此,我的问题是:如何更改此行为以获得此验证消息:

{
  "screen_width": [
    "Required width"
  ]
}

PS我使用.NET Core 3.1,并且using Newtonsoft.Json;用于[JsonProperty]属性。

卡萨拉斯(Athanasios Kataras)

我来到这里的以下有趣的文章

请尝试以下操作:

public class MyModel
{
     [JsonProperty("screen_width")]
     [Required(ErrorMessage = "Required width")]
     [DisplayName("screen_width")]
     public string ScreenWidth { get; set; }  
}

但是,这本身是行不通的。您需要禁用内部模型状态过滤器。

public void ConfigureServices(IServiceCollection services)  
    {  
        ...  
        services.Configure<ApiBehaviorOptions>(options =>  
            {  
                options.SuppressModelStateInvalidFilter = true;  
            });  
        ...  
    }  

然后,创建另一个过滤器

public class DisplayNameValidationFilterAttribute : ActionFilterAttribute  
{  
    public override void OnActionExecuting(ActionExecutingContext context)  
    {  
        if (context.ModelState.ErrorCount > 0)  
        {  
            var modelType = context.ActionDescriptor.Parameters  
                .FirstOrDefault(p => p.BindingInfo.BindingSource.Id.Equals("Body", StringComparison.InvariantCultureIgnoreCase))?.ParameterType; //Get model type  

            var expandoObj = new ExpandoObject();  
            var expandoObjCollection = (ICollection<KeyValuePair<String, Object>>)expandoObj; //Cannot convert IEnumrable to ExpandoObject  

            var dictionary = context.ModelState.ToDictionary(k => k.Key, v => v.Value)  
                .Where(v => v.Value.ValidationState == ModelValidationState.Invalid)  
                .ToDictionary(  
                k =>  
                {  
                    if (modelType != null)  
                    {  
                        var property = modelType.GetProperties().FirstOrDefault(p => p.Name.Equals(k.Key, StringComparison.InvariantCultureIgnoreCase));  
                        if (property != null)  
                        {  
                            //Try to get the attribute  
                            var displayName = property.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault()?.DisplayName;  
                            return displayName ?? property.Name;  
                        }  
                    }  
                    return k.Key; //Nothing found, return original vaidation key  
                },  
                v => v.Value.Errors.Select(e => e.ErrorMessage).ToList() as Object); //Box String collection  
            foreach (var keyValuePair in dictionary)  
            {  
                expandoObjCollection.Add(keyValuePair);  
            }  
            dynamic eoDynamic = expandoObj;  
            context.Result = new BadRequestObjectResult(eoDynamic);  
        }  
        base.OnActionExecuting(context);  
    }  
}  

现在只需使用以下命令:

public class MyController
{
    [Route("/api/v1.0/test")]
    [DisplayNameValidationFilter]  
    [HttpPatch]
    public async Task<IActionResult> SomeAction([FromBody] MyModel viewModel)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

Related 相关文章

热门标签

归档