gpt4 book ai didi

asp.net-mvc-3 - MVC 3复杂的模型验证

转载 作者:行者123 更新时间:2023-12-01 23:50:35 25 4
gpt4 key购买 nike

当前在MVC 3中使用的验证方法似乎是ValidationAttributes。我有一个非常特定于该模型的类验证,并且在几个属性之间具有交互作用。

基本上,模型具有其他模型的集合,并且都以相同的形式对其进行编辑。我们称之为ModelA,它具有ModelB的集合。我可能需要验证的一件事是,ModelB的某些属性的总和小于ModelA的属性。用户拥有X个点数,他可以在一些选项之间进行划分。

ValidationAttributes非常通用,我不确定它们是否适合此工作。

我不知道MVC 3中如何支持IDateErrorInfo,以及它是否可以直接使用。

一种方法是通过一种方法进行验证,但这意味着我无法进行客户端验证。

做这样的事情的正确方法是什么?我还有其他选择吗?我是否低估了ValidationAttribute的功能?

最佳答案

IDateErrorInfo

MVC框架支持IDateErrorInfo(可以在here中找到Microsoft教程)。通过将html表单元素绑定到模型,默认的模型绑定器将负责重新创建模型对象。如果模型绑定程序检测到模型实现了接口,则它将使用接口方法来验证模型中的每个属性或验证整个模型。有关更多信息,请参见教程。

如果您想通过这种方法使用客户端验证,那么(引用史蒂夫·桑德森的话)“利用其他验证规则的最直接方法是在视图中手动生成所需的属性”:

<p>
@Html.TextBoxFor(m.ClientName, new { data_val = "true", data_val_email = "Enter a valid email address", data_val_required = "Please enter your name"})

@Html.ValidationMessageFor(m => m.ClientName)
</p>


然后可以将其用于触发已定义的任何客户端验证。请参阅以下示例,以了解如何定义客户端验证。

显式验证

如前所述,您可以在操作中明确验证模型。例如:

public ViewResult Register(MyModel theModel)
{
if (theModel.PropertyB < theModel.PropertyA)
ModelState.AddModelError("", "PropertyA must not be less then PropertyB");

if (ModelState.IsValid)
{
//save values
//go to next page
}
else
{
return View();
}
}


然后,在视图中,您将需要使用 @Html.ValidationSummary来显示错误消息,因为上面的代码会添加模型级别的错误,而不是属性级别的错误。

要指定属性级别错误,您可以编写:

ModelState.AddModelError("PropertyA", "PropertyA must not be less then PropertyB");


然后在视图中使用:

@Html.ValidationMessageFor(m => m.PropertyA);


显示错误信息。

同样,需要通过定义属性在视图中手动链接客户端验证来链接任何客户端验证。

自定义模型验证属性

如果我正确理解了该问题,则您正在尝试验证包含单个值和一个集合的属性的模型,该集合中的属性将被求和。

对于我将给出的示例,该视图将向用户显示一个最大值字段和5个值字段。最大值字段将是模型中的单个值,其中5个值字段将成为集合的一部分。验证将确保值字段的总和不大于最大值字段。验证将定义为模型上的一个属性,该属性还将很好地链接到javascript客户端评估。

风景:

@model MvcApplication1.Models.ValueModel

<h2>Person Ages</h2>

@using (@Html.BeginForm())
{
<p>Please enter the maximum total that will be allowed for all values</p>
@Html.EditorFor(m => m.MaximumTotalValueAllowed)
@Html.ValidationMessageFor(m => m.MaximumTotalValueAllowed)

int numberOfValues = 5;

<p>Please enter @numberOfValues different values.</p>

for (int i=0; i<numberOfValues; i++)
{
<p>@Html.EditorFor(m => m.Values[i])</p>
}

<input type="submit" value="submit"/>
}


我没有对值字段添加任何验证,因为我不想使示例过于复杂。

该模型:

public class ValueModel
{
[Required(ErrorMessage="Please enter the maximum total value")]
[Numeric] //using DataAnnotationExtensions
[ValuesMustNotExceedTotal]
public string MaximumTotalValueAllowed { get; set; }

public List<string> Values { get; set; }
}


行动:

public ActionResult Index()
{
return View();
}

[HttpPost]
public ActionResult Index(ValueModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
else
{
return RedirectToAction("complete"); //or whatever action you wish to define.
}
}


自定义属性:

可以通过重写ValidationAttribute类来定义在模型上定义的 [ValuesMustNotExceedTotal]属性:

public class ValuesMustNotExceedTotalAttribute : ValidationAttribute
{
private int maxTotalValueAllowed;
private int valueTotal;

public ValuesMustNotExceedTotalAttribute()
{
ErrorMessage = "The total of all values ({0}) is greater than the maximum value of {1}";
}

public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, valueTotal, maxTotalValueAllowed);
}

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
PropertyInfo maxTotalValueAllowedInfo = validationContext.ObjectType.GetProperty("MaximumTotalValueAllowed");
PropertyInfo valuesInfo = validationContext.ObjectType.GetProperty("Values");

if (maxTotalValueAllowedInfo == null || valuesInfo == null)
{
return new ValidationResult("MaximumTotalValueAllowed or Values is undefined in the model.");
}

var maxTotalValueAllowedPropertyValue = maxTotalValueAllowedInfo.GetValue(validationContext.ObjectInstance, null);
var valuesPropertyValue = valuesInfo.GetValue(validationContext.ObjectInstance, null);

if (maxTotalValueAllowedPropertyValue != null && valuesPropertyValue != null)
{
bool maxTotalValueParsed = Int32.TryParse(maxTotalValueAllowedPropertyValue.ToString(), out maxTotalValueAllowed);

int dummyValue;
valueTotal = ((List<string>)valuesPropertyValue).Sum(x => Int32.TryParse(x, out dummyValue) ? Int32.Parse(x) : 0);

if (maxTotalValueParsed && valueTotal > maxTotalValueAllowed)
{
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
}

//if the maximum value is not supplied or could not be parsed then we still return that the validation was successful.
//why? because this attribute is only responsible for validating that the total of the values is less than the maximum.
//we use a [Required] attribute on the model to ensure that the field is required and a [Numeric] attribute
//on the model to ensure that the fields are input as numeric (supplying appropriate error messages for each).
return null;
}
}


将客户端验证添加到“自定义”属性中:

要将客户端验证添加到此属性,它将需要实现IClientValidatable接口:

public class ValuesMustNotExceedTotalAttribute : ValidationAttribute, IClientValidatable
{
//...code as above...

//this will be called when creating the form html to set the correct property values for the form elements
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule {
ValidationType = "valuesmustnotexceedtotal", //the name of the client side javascript validation (must be lowercase)
ErrorMessage = "The total of all values is greater than the maximum value." //I have provided an alternative error message as i'm not sure how you would alter the {0} and {1} in javascript.
};

yield return rule;
//note: if you set the validation type above to "required" or "email" then it would use the default javascript routines (by those names) to validate client side rather than the one we define
}
}


如果此时要运行该应用程序并查看用于定义属性的字段的源html,则会看到以下内容:

<input class="text-box single-line" data-val="true" data-val-number="The MaximumTotalValueAllowed field is not a valid number." data-val-required="Please enter the maximum total value" data-val-valuesmustnotexceedtotal="The total of all values is greater than the maximum value." id="MaximumTotalValueAllowed" name="MaximumTotalValueAllowed" type="text" value="" />


特别注意 data-val-valuesmustnotexceedtotal的验证属性。这就是我们的客户端验证将如何链接到验证属性。

添加客户端验证:

要添加客户端验证,您需要在视图的标记中添加以下类似的库引用:

<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>


您还需要确保在web.config中启用了客户端验证,尽管我认为默认情况下应启用该验证:

<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>


剩下的就是在视图中定义客户端验证。请注意,此处添加的验证是在视图中定义的,但是如果在库中定义了验证,则可以将自定义属性(可能不是此属性)添加到其他视图的其他模型中:

<script type="text/javascript">

jQuery.validator.unobtrusive.adapters.add('valuesmustnotexceedtotal', [], function (options) {
options.rules['valuesmustnotexceedtotal'] = '';
options.messages['valuesmustnotexceedtotal'] = options.message;
});

//note: this will only be fired when the user leaves the maximum value field or when the user clicks the submit button.
//i'm not sure how you would trigger the validation to fire if the user leaves the value fields although i'm sure its possible.
jQuery.validator.addMethod('valuesmustnotexceedtotal', function (value, element, params) {

sumValues = 0;

//determine if any of the value fields are present and calculate the sum of the fields
for (i = 0; i <= 4; i++) {

fieldValue = parseInt($('#Values_' + i + '_').val());

if (!isNaN(fieldValue)) {
sumValues = sumValues + fieldValue;
valueFound = true;
}
}

maximumValue = parseInt(value);

//(if value has been supplied and is numeric) and (any of the fields are present and are numeric)
if (!isNaN(maximumValue) && valueFound) {

//perform validation

if (sumValues > maximumValue)
{
return false;
}
}

return true;
}, '');

</script>


就是这样。我确信可以在这里和那里进行改进,并且如果我对这个问题有轻微的误解,那么您应该可以根据需要调整验证。但是我相信这种验证似乎是大多数开发人员编写自定义属性(包括更复杂的客户端验证)的方式。

希望这可以帮助。如果您对以上内容有任何疑问或建议,请告诉我。

关于asp.net-mvc-3 - MVC 3复杂的模型验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7979115/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com