【问题标题】:Integer value model validation整数值模型验证
【发布时间】:2014-08-17 13:07:24
【问题描述】:

我的模型中有一个常规整数(不可为空):

    [Required]
    [Range(0, Int32.MaxValue - 1)]
    public int PersonId
    {
        get;
        set;
    }

在我的WebApi 操作中,我接受具有该属性的对象。

    public IHttpActionResult Create([FromBody] Person person)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest("Some error message.");
        } 
        //Do some stuff with person...
    }

现在,虽然PersonId 上有一个Required 属性,但当一个人发布到此操作时,ModelState.IsValid 属性是true

我猜这是因为Person是使用默认值创建的,即0,如果传入的JSON/查询字符串请求中没有PersonId字段,我想抛出错误。

我可以将 PersonId 设置为 Nullable,但这没有意义。

是否有任何简单的方法来验证字段是否存在且整数大于 0 ? (没有针对该简单要求的自定义验证器)

【问题讨论】:

    标签: asp.net asp.net-web-api2 model-validation


    【解决方案1】:

    据我所知,设置 [Required] 属性不会对 int 执行任何操作。 [Required] 所做的只是确保该值不为空。 您可以设置[Range(1, Int32.MaxValue)] 以确保添加了正确的值。

    如果您还没有这样做,最好为您的视图创建一个不同的模型并在此模型上进行数据注释。我使用视图模型来确保我不会用与整个域无关的东西污染我的“真实”模型。这样,您的 PersonId 只能在您的视图模型中为空,这是有意义的。

    【讨论】:

      【解决方案2】:

      BindRequiredAttribute可以用来

      引用此nice blog post 关于[Required][BindRequired]

      它的工作方式与RequiredAttribute 相同,只是它要求 该值来自请求——因此它不仅拒绝空值, 还有默认(或“未绑定”)值。

      所以这会拒绝未绑定的整数值:

      [BindRequired]
      [Range(0, Int32.MaxValue - 1)]
      public int PersonId
      {
          get;
          set;
      }
      

      【讨论】:

      • 当我遇到输入来自 [FromBody] 的类似问题时,我偶然发现了这一点。因此,要在答案上方添加异常,在使用输入格式化程序又名 [FromBody] 时,[BindRequired] 不相关。见Github
      【解决方案3】:

      在这种情况下,我倾向于使用int?(可为空的int),然后根据需要标记它们。然后我在整个代码中使用myInt.Value,并假设它可以安全使用,否则它不会通过验证。

      就像@andreas 所说,我确实确保在这种情况下使用“视图模型”,这样我就不会污染我的视图模型作为业务或数据层模型。

      【讨论】:

        【解决方案4】:

        实际上,对于缺少不可为空的整数参数,模型验证不起作用。 Newtonsoft.Json 抛出 JSON 解析异常。 您可以使用以下解决方法在模型验证中解析和包含异常。 如下创建自定义验证属性并在 WebApiConfig.cs 中注册。

        public class ValidateModelAttribute : ActionFilterAttribute {
            public override void OnActionExecuting(HttpActionContext actionContext) {
                // Check if model state is valid
                if (actionContext.ModelState.IsValid == false) {
                    // Return model validations object
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest,
                                                                                    new ValidationResultModel(100001, actionContext.ModelState));
                }
            }
        
            public class ValidationError {
                public string Field { get; }
        
                public string Message { get; }
        
                public ValidationError(string field, string message) {
                    Field = field != string.Empty ? field : null;
                    Message = message;
                }
            }
        
            public class ValidationResultModel {
                public int Code { get; set; }
                public string Message { get; }
                public IDictionary<string, IEnumerable<string>> ModelState { get; private set; }
        
                public ValidationResultModel(int messageCode, ModelStateDictionary modelState) {
                    Code = messageCode;
                    Message = "Validation Failed";
        
                    ModelState = new Dictionary<string, IEnumerable<string>>();
        
                    foreach (var keyModelStatePair in modelState) {
                        var key = string.Empty;
                        key = keyModelStatePair.Key;
                        var errors = keyModelStatePair.Value.Errors;
                        var errorsToAdd = new List<string>();
        
                        if (errors != null && errors.Count > 0) {
                            foreach (var error in errors) {
                                string errorMessageToAdd = error.ErrorMessage;
        
                                if (string.IsNullOrEmpty(error.ErrorMessage)) {
                                    if (key == "model") {
                                        Match match = Regex.Match(error.Exception.Message, @"'([^']*)");
                                        if (match.Success)
                                            key = key + "." + match.Groups[1].Value;
        
                                        errorMessageToAdd = error.Exception.Message;
                                    } else {
                                        errorMessageToAdd = error.Exception.Message;
                                    }
                                }
        
                                errorsToAdd.Add(errorMessageToAdd);
                            }
        
                            ModelState.Add(key, errorsToAdd);
                        }
                    }
                }
            }
        }
        

        //在WebApiConfig.cs中注册

        // Model validation           
           config.Filters.Add(new ValidateModelAttribute());
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-01-12
          • 2018-08-24
          • 2020-12-28
          • 1970-01-01
          • 2017-10-12
          • 1970-01-01
          相关资源
          最近更新 更多