为了使用Regex进行验证,我通常这样做:
// In my ViewModel
[RegularExpression("MyRegex", ErrorMessageResourceName = "MyErrorMessage")]
public string MyField { get; set; }
和HTML助手
@Html.TextBoxFor(model => model.MyField)
生成如下所示的标记:
<input type="text" class="valid" name="MyField" value="" id="MyField" data-val="true" data-val-regex-pattern="MyRegex" data-val-regex="MyErrorMessage"></input>
问题是,我希望有一个动态的字段数,现在正在使用
// In my ViewModel
[RegularExpression("MyRegex", ErrorMessageResourceName = "MyErrorMessage")]
public IList<string> MyField { get; set; }
这一次
@Html.TextBoxFor(model => model.MyField[0])
将生成(没有regex属性)
<input id="MyField_0_" type="text" value="" name="MyField[0]"></input>
如何确保在绑定在我的data-val
中具有DataAnnotation验证属性的列表的元素时创建ViewModel html属性?
发布于 2014-05-02 09:26:52
实际上,没有一种方法可以将数据注释应用于列表的元素。您需要做的是创建一个包装类并将数据注释应用于包装类中的元素,如下所示:
public IList<MyField> MyFields {get;set;}
public class MyField
{
[RegularExpression("MyRegex", ErrorMessageResourceName = "MyErrorMessage")]
public string Value
}
用法:
@Html.TextBoxFor(model => model.MyFields[0].Value)
发布于 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元素中来实现您想要的结果。
这可以通过
下面给出了step1的共享编辑器模板
@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中,输入以下代码-
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new DAModelValidatorProvider());
ModelMetadataProviders.Current = new CachedDataAnnotationsModelMetadataProvider();
步骤3-通过重写ModelValidatorProvider方法编写自己的GetValidators,如下面的代码所示
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上,这样您就可以试一试,看看它是否适合您的需要。我在这里所做的并不是一个完全的解决方案,但希望它能让你不必改变你的模型。
干杯,斯沃拉普。
发布于 2015-02-26 13:27:04
我使用@swazza85 85回答,但不得不根据我的情况修改它。希望如果其他人使用他的解决方案,他们可以受益于我的修改。我不得不将IEnumerable<object>
更改为IList<object>
(在我的例子中是IList<decimal?>
,因为IList<object>
抛出了一个错误)。然后我必须使用for
迭代器,因为单词item
被添加到name属性中,而且模型绑定器没有将这些项绑定到我的模型中。
@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
。
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>();
}
https://stackoverflow.com/questions/23337170
复制相似问题