【问题标题】:ASP.NET RC2 - ModelState doesn't validate elements of collectionASP.NET RC2 - ModelState 不验证集合的元素
【发布时间】:2016-11-25 02:06:16
【问题描述】:

假设我有一个简单的模型,属性高于属性。

public class User
{
    [Required]
    string Name {get;set;}
    string Surname {get;set;}
}

当我 POST/PUT 只有一个 User 和 Name 实例为空时,它工作得很好。 ModelState 无效并包含错误。

当我 POST/PUT 对象集合 User 并且其中一些 Name 为空时,ModelState 有效并且不包含任何验证错误。

你能告诉我它有什么问题吗?为什么它只涉及收藏?当我有一个具有一对多关系的对象时,我注意到了同样的行为。然后这个对象内的集合也不会被 ModelState 验证。

我不想手动验证必填字段,它应该会自动工作。

【问题讨论】:

  • 验证是属性级别的,有一种解决方法可以将集合作为属性放入模型中。

标签: asp.net validation asp.net-core modelstate


【解决方案1】:

你需要创建一个 ActionFilter

public class ModelStateValidActionFilter : IAsyncActionFilter
{
    public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // Validate ICollection
        if (context.ActionArguments.Count == 1 && context.ActionArguments.First().Value.GetType().IsListType())
        {
            foreach (var arg in (IList)context.ActionArguments.First().Value  )
            {
                var parameters = arg.GetType().GetProperties();
                foreach (var parameter in parameters)
                {
                    var argument = context.ActionArguments.GetOrDefault(parameter.Name);
                    EvaluateValidationAttributes(parameter, argument, context.ModelState);
                }
            }
        }

        if (context.ModelState.IsValid)
        {
            return next();
        }
        context.Result = new BadRequestObjectResult(context.ModelState);
        return Task.CompletedTask;
    }

    private void EvaluateValidationAttributes(PropertyInfo parameter, object argument, ModelStateDictionary modelState)
    {
        var validationAttributes = parameter.CustomAttributes;
        foreach (var attributeData in validationAttributes)
        {
            var attributeInstance = parameter.GetCustomAttribute(attributeData.AttributeType);
            var validationAttribute = attributeInstance as ValidationAttribute;
            if (validationAttribute != null)
            {
                var isValid = validationAttribute.IsValid(argument);
                if (!isValid)
                {
                    modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name));
                }
            }
        }
    }

并将其添加到您的 MVC 选项中

services.AddMvc()
    .AddMvcOptions(opts =>
    {
        opts.Filters.Add(new ModelStateValidActionFilter());
    }

【讨论】:

  • 这如何解决验证集合的问题?
  • 如果集合是一个属性,你可以实现IValidatableObject来验证它,但似乎没有办法验证一个根集合。验证仅适用于“属性级”属性。
  • 我不敢相信它不会自动工作。如果我们有嵌套模型,例如用户,它有一个地址作为属性,而地址有空的必需属性,我们会得到一个错误。一定有收藏的东西……
  • 是的。它不会由 ModelState.IsValid 自动工作,但您仍然可以使其与 ActionFilter 一起工作,这使您可以进行额外的验证。我更新了我的答案,您可能需要润色代码,但它是一种使之成为可能的解决方案,您也可以以相同的方式验证查询字符串。 ValidationActionFilter 的另一个优点是您可以从所有控制器中删除所有 ModelState.IsValid。我不知道谁取消了投票,为什么,请投票。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多