在ModelState.Errors中使用[JsonProperty(“name”))

问题描述:

我们有几个通过JsonProperty覆盖名称的模型,但是当我们通过ModelState获取验证错误时,这会导致问题。例如:在ModelState.Errors中使用[JsonProperty(“name”))

class MyModel 
{ 
    [JsonProperty("id")] 
    [Required] 
    public string MyModelId {get;set;} 
} 

class MyModelController 
{ 
    public IHttpActionResult Post([FromBody] MyModel model) 
    { 
     if (!ModelState.IsValid) 
     { 
      return HttpBadRequest(ModelState); 
     } 

     /* etc... */ 
    } 
} 

上述帖子将返回错误The MyModelId field is required.,这是不准确的。我们希望这样说The id field is required.。我们尝试使用[DataMember(Name="id")],但得到相同的结果。

问题1:有没有一种方法,我们可以得到的ModelState错误,从每一个[必需]属性为我们自己的错误信息显示JSON属性名称,而不是C#属性名称预留?

- 更新 -

我一直在玩这个了一圈,发现重新创建使用自定义属性名称错误消息的“做自己动手”的方法。我真的希望有一个内置的方式做到这一点,但这似乎做的工作......

https://gist.github.com/Blackbaud-JasonTremper/b64dc6ddb460afa1698daa6d075857e4

问题2:可以ModelState.Key被认为符合<parameterName>.<reflectedProperty>语法或者有没有这种情况下,这可能是不正确的?

问题3:有没有更简单的方法,以确定哪些JSON参数名预计,而不是通过反思[DataMember][JsonProperty]属性搜索?

您是否尝试过使用DisplayName属性?

displayname attribute vs display attribute

此外,您还可以指定一个错误消息[Required]属性。

[Required(ErrorMessage = "Name is required")]

+0

我也尝试[显示名称],并没有奏效。然而根据你的链接,[Display]属性完成了这项工作(也许这就是你的意思?)。谢谢! – jt000

我也面临这个问题,我修改了一些代码,从你的链接,以适合我的WebAPI。 modelState也将存储模型的变量名称的旧密钥以及Json属性名称。

  1. 首先,创建过滤器ValidateModelStateFilter
  2. 添加[ValidateModelStateFilter]上述控制器方法

过滤器的源代码:

public class ValidateModelStateFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var descriptor = actionContext.ActionDescriptor; 
     var modelState = actionContext.ModelState; 

     if (descriptor != null) 
     { 
      var parameters = descriptor.GetParameters(); 

      var subParameterIssues = modelState.Keys 
               .Where(s => s.Contains(".")) 
               .Where(s => modelState[s].Errors.Any()) 
               .GroupBy(s => s.Substring(0, s.IndexOf('.'))) 
               .ToDictionary(g => g.Key, g => g.ToArray()); 

      foreach (var parameter in parameters) 
      { 
       var argument = actionContext.ActionArguments[parameter.ParameterName]; 

       if (subParameterIssues.ContainsKey(parameter.ParameterName)) 
       { 
        var subProperties = subParameterIssues[parameter.ParameterName]; 
        foreach (var subProperty in subProperties) 
        { 
         var propName = subProperty.Substring(subProperty.IndexOf('.') + 1); 
         var property = parameter.ParameterType.GetProperty(propName); 
         var validationAttributes = property.GetCustomAttributes(typeof(ValidationAttribute), true); 

         var value = property.GetValue(argument); 

         modelState[subProperty].Errors.Clear(); 
         foreach (var validationAttribute in validationAttributes) 
         { 
          var attr = (ValidationAttribute)validationAttribute; 
          if (!attr.IsValid(value)) 
          { 
           var parameterName = GetParameterName(property); 
           // modelState.AddModelError(subProperty, attr.FormatErrorMessage(parameterName)); 
           modelState.AddModelError(parameterName, attr.FormatErrorMessage(parameterName)); 
          } 
         } 
        } 
       } 


      } 
     } 

    } 

    private string GetParameterName(PropertyInfo property) 
    { 
     var dataMemberAttribute = property.GetCustomAttributes<DataMemberAttribute>().FirstOrDefault(); 
     if (dataMemberAttribute?.Name != null) 
     { 
      return dataMemberAttribute.Name; 
     } 

     var jsonProperty = property.GetCustomAttributes<JsonPropertyAttribute>().FirstOrDefault(); 
     if (jsonProperty?.PropertyName != null) 
     { 
      return jsonProperty.PropertyName; 
     } 

     return property.Name; 
    } 
} 
+0

有没有AspNetCore的这个版本?谢谢 –