首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对我的ViewModel列表中的每个项进行数据验证

对我的ViewModel列表中的每个项进行数据验证
EN

Stack Overflow用户
提问于 2014-04-28 09:19:35
回答 3查看 7.4K关注 0票数 6

为了使用Regex进行验证,我通常这样做:

代码语言:javascript
运行
复制
// In my ViewModel
[RegularExpression("MyRegex", ErrorMessageResourceName = "MyErrorMessage")]
public string MyField { get; set; }

和HTML助手

代码语言:javascript
运行
复制
@Html.TextBoxFor(model => model.MyField)

生成如下所示的标记:

代码语言:javascript
运行
复制
<input type="text" class="valid" name="MyField" value="" id="MyField" data-val="true" data-val-regex-pattern="MyRegex" data-val-regex="MyErrorMessage"></input>

问题是,我希望有一个动态的字段数,现在正在使用

代码语言:javascript
运行
复制
// In my ViewModel
[RegularExpression("MyRegex", ErrorMessageResourceName = "MyErrorMessage")]
public IList<string> MyField { get; set; }

这一次

代码语言:javascript
运行
复制
@Html.TextBoxFor(model => model.MyField[0])

将生成(没有regex属性)

代码语言:javascript
运行
复制
<input id="MyField_0_" type="text" value="" name="MyField[0]"></input>

如何确保在绑定在我的data-val中具有DataAnnotation验证属性的列表的元素时创建ViewModel html属性?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-05-02 09:26:52

实际上,没有一种方法可以将数据注释应用于列表的元素。您需要做的是创建一个包装类并将数据注释应用于包装类中的元素,如下所示:

代码语言:javascript
运行
复制
public IList<MyField> MyFields {get;set;}

public class MyField
{
    [RegularExpression("MyRegex", ErrorMessageResourceName = "MyErrorMessage")]
    public string Value
}

用法:

代码语言:javascript
运行
复制
@Html.TextBoxFor(model => model.MyFields[0].Value)
票数 10
EN

Stack Overflow用户

发布于 2014-05-02 21:42:28

您正在使用DataAnnotations进行验证。据我所知,您正在寻找一种将DataAnnotation验证应用于列表中每个元素的方法。

每当调用Html.EditorFor时,它都会获取传递给它的模型的ModelMetadata,然后获取与该模型关联的任何ModelValidators。正是这些ModelValidators的存在导致了‘dat-val-*’属性在HTML中的出现。

当Html.EditorFor作为模型(或任何可枚举的模型)传递列表时,它首先获取属性的ModelMetadata和相关验证器--在您的示例中,它将获取与'MyField‘属性关联的ModelMetadata,在本例中将获取与验证器- 'RegularExpression’相关联的验证器。接下来,它遍历字符串列表,并获取每个字符串的ModelMetadata和验证器。虽然已经为每个字符串构造了ModelMetadata,但是没有为这些字符串指定任何验证器。这就是显示字符串的原因,但验证属性没有添加到HTML元素中。

在我看来,可以通过在运行时将在“MyField”属性上指定的Validator添加到所有list元素中来实现您想要的结果。

这可以通过

  1. 为所有集合编写共享编辑器模板
  2. 将当前ModelMetadataProvider设置为DataAnnotationsModelMetadataProvider
  3. 重写“GetValidators”的DataAnnotationsModelValidatorProvider方法

下面给出了step1的共享编辑器模板

代码语言:javascript
运行
复制
@model System.Collections.Generic.IEnumerable<object>
@{
    ViewBag.Title = "Collection";
    var modelMetadata = this.ViewData.ModelMetadata;
    var validators = modelMetadata.GetValidators(ViewContext).ToList();
    ViewContext.HttpContext.Items["rootValidators"] = validators;
}

@foreach (var item in Model)
{
    @Html.EditorFor(m => item)
}

您可以在上面的代码中看到,我们正在获取列表中指定的所有验证器。这些验证器稍后将添加到列表的元素中。它们已经存储在HttpContext.Items中,以便在我们的自定义ModelValidatorProvider中使用。

步骤2-在Global.asax中,输入以下代码-

代码语言:javascript
运行
复制
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new DAModelValidatorProvider());

ModelMetadataProviders.Current = new CachedDataAnnotationsModelMetadataProvider();

步骤3-通过重写ModelValidatorProvider方法编写自己的GetValidators,如下面的代码所示

代码语言:javascript
运行
复制
public class DAModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        var validators = base.GetValidators(metadata, context, attributes).ToList();

        // get root validators of the collection. this was stored in the editor template - fetching it for use now.
        // fetching the rootvalidators inside this method is a bad idea because we have to call GetValidators method on the 
        // containers ModelMetadata and it will result in a non-terminal recursion
        var rootValidators = context.HttpContext.Items["rootValidators"] as IEnumerable<ModelValidator>;
        if (rootValidators != null)
        {
            foreach (var rootValidator in rootValidators)
            {
                validators.Add(rootValidator);
            }
        }

        return validators;
    }
}

执行上述三个步骤对我来说是有效的。但是,我使用的是Html.EditorFor而不是Html.TextBoxFor。使用Html.EditorFor时,我没有给出正确的id和name属性--我认为这在事物方案中是一个微不足道的问题。我已经为此创建了一个解决方案,并将其上传到https://github.com/swazza85/Stackoverflow上,这样您就可以试一试,看看它是否适合您的需要。我在这里所做的并不是一个完全的解决方案,但希望它能让你不必改变你的模型。

干杯,斯沃拉普。

票数 4
EN

Stack Overflow用户

发布于 2015-02-26 13:27:04

我使用@swazza85 85回答,但不得不根据我的情况修改它。希望如果其他人使用他的解决方案,他们可以受益于我的修改。我不得不将IEnumerable<object>更改为IList<object> (在我的例子中是IList<decimal?>,因为IList<object>抛出了一个错误)。然后我必须使用for迭代器,因为单词item被添加到name属性中,而且模型绑定器没有将这些项绑定到我的模型中。

代码语言:javascript
运行
复制
@model System.Collections.Generic.IList<decimal?>

@{
    ViewBag.Title = "Collection";
    var modelMetadata = this.ViewData.ModelMetadata;
    var validators = modelMetadata.GetValidators(ViewContext).ToList();
    ViewContext.HttpContext.Items["rootValidators"] = validators;
}

@for (var i = 0; i < Model.Count(); i++)
{
    @Html.EditorFor(model => Model[i], new { htmlAttributes = new { @class = "form-control" } })
    @Html.ValidationMessageFor(model => Model[i], "", new { @class = "text-danger" })
}

另外,如果不想清除Global.asax文件中的提供程序,只需返回if语句中的验证器并在其外部返回一个空列表,只需注意此编辑器模板必须是视图中的最后一个,否则它将遇到其他属性或模板的问题。您可以在模板的末尾设置ViewContext.HttpContext.Items["rootValidators"] = null

代码语言:javascript
运行
复制
  protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
      var validators = base.GetValidators(metadata, context, attributes).ToList();

      // get root validators of the collection. this was stored in the editor template - fetching it for use now.
      // fetching the rootvalidators inside this method is a bad idea because we have to call GetValidators method on the 
      // containers ModelMetadata and it will result in a non-terminal recursion
      var rootValidators = context.HttpContext.Items["rootValidators"] as IEnumerable<ModelValidator>;

      if (rootValidators != null)
      {
        foreach (var rootValidator in rootValidators)
        {
          validators.Add(rootValidator);
        }
        return validators;
      }

      return new List<ModelValidator>();
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23337170

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档