C# ASP.NET MVC条件验证
如何使用数据注释对模型进行条件验证 例如,假设我们有以下模型(个人和高级): 以及以下观点:C# ASP.NET MVC条件验证,c#,asp.net-mvc,forms,validation,C#,Asp.net Mvc,Forms,Validation,如何使用数据注释对模型进行条件验证 例如,假设我们有以下模型(个人和高级): 以及以下观点: <%= Html.EditorFor(m => m.Name)%> <%= Html.ValidationMessageFor(m => m.Name)%> <%= Html.CheckBoxFor(m => m.IsSenior)%> <%= Html.ValidationMessageFor(m => m.IsSenior)%>
<%= Html.EditorFor(m => m.Name)%>
<%= Html.ValidationMessageFor(m => m.Name)%>
<%= Html.CheckBoxFor(m => m.IsSenior)%>
<%= Html.ValidationMessageFor(m => m.IsSenior)%>
<%= Html.CheckBoxFor(m => m.Senior.Description)%>
<%= Html.ValidationMessageFor(m => m.Senior.Description)%>
m.Name)%%>
m、 名称)%%>
m、 IsSenior)%%>
m、 IsSenior)%%>
m、 高级(说明)%>
m、 高级(说明)%>
我想成为“Senior.Description”属性条件必填字段,该字段基于对“IsSenior”属性的选择(true->required)。如何使用数据注释在ASP.NET MVC 2中实现条件验证?您需要在人员级别进行验证,而不是在高级级别,或者高级必须有对其父级人员的引用。在我看来,您需要一个自我验证机制来定义对个人的验证,而不是对其属性之一的验证。我不确定,但我认为DataAnnotations不支持这种开箱即用的方式。您可以创建自己的
属性
,该属性派生自ValidationAttribute
,可以在类级别上进行修饰,然后创建一个自定义验证器,该验证器还允许这些类级别的验证器运行
我知道验证应用程序块支持开箱即用的自我验证,但VAB有一个相当陡峭的学习曲线。然而,这里有一个使用VAB的示例:
[HasSelfValidation]
public class Person
{
public string Name { get; set; }
public bool IsSenior { get; set; }
public Senior Senior { get; set; }
[SelfValidation]
public void ValidateRange(ValidationResults results)
{
if (this.IsSenior && this.Senior != null &&
string.IsNullOrEmpty(this.Senior.Description))
{
results.AddResult(new ValidationResult(
"A senior description is required",
this, "", "", null));
}
}
}
我通过处理控制器包含的字典解决了这个问题。ModelState字典包含所有必须验证的成员 以下是解决方案: 如果您需要基于某个字段实现条件验证(例如,如果a=true,则需要B),同时维护属性级错误消息传递(对于对象级的自定义验证器不是这样),您可以通过处理“ModelState”来实现,只需从中删除不需要的验证 …在某个班级
public bool PropertyThatRequiredAnotherFieldToBeFilled
{
get;
set;
}
[Required(ErrorMessage = "*")]
public string DepentedProperty
{
get;
set;
}
…课程继续
…在某些控制器操作中
if (!PropertyThatRequiredAnotherFieldToBeFilled)
{
this.ModelState.Remove("DepentedProperty");
}
通过这一点,我们实现了条件验证,而其他一切都保持不变。
更新: 这是我的最后一个实现:我在模型上使用了一个接口和action属性,该属性验证了实现所述接口的模型。接口规定了验证(ModelStateDictionary modelState)方法。action上的属性只调用IValidatorSomething上的Validate(modelState)
我不想让这个答案复杂化,所以我没有提到最终的实现细节(最后,这在生产代码中很重要)。您可以通过删除ModelState中的错误有条件地禁用验证器:
ModelState["DependentProperty"].Errors.Clear();
看看西蒙·因斯的
我现在正在完成他的示例项目。谢谢:)
我刚刚将其更新到MVC 3,以防有人发现它有用:。有一种更好的方法可以在MVC3中添加条件验证规则;让您的模型继承
IValidatableObject
并实现Validate
方法:
public class Person : IValidatableObject
{
public string Name { get; set; }
public bool IsSenior { get; set; }
public Senior Senior { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (IsSenior && string.IsNullOrEmpty(Senior.Description))
yield return new ValidationResult("Description must be supplied.");
}
}
公共类人物:IValidatableObject
{
公共字符串名称{get;set;}
公共布尔IsSenior{get;set;}
公共高级{get;set;}
公共IEnumerable验证(ValidationContext ValidationContext)
{
if(IsSenior&&string.IsNullOrEmpty(高级描述))
返回新的ValidationResult(“必须提供说明”);
}
}
阅读更多信息。我昨天也遇到了同样的问题,但我以一种非常干净的方式解决了这个问题,它适用于客户端和服务器端验证 条件:根据模型中其他属性的值,您希望使另一个属性成为必需的。这是密码
public class RequiredIfAttribute : RequiredAttribute
{
private String PropertyName { get; set; }
private Object DesiredValue { get; set; }
public RequiredIfAttribute(String propertyName, Object desiredvalue)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
Object instance = context.ObjectInstance;
Type type = instance.GetType();
Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
if (proprtyvalue.ToString() == DesiredValue.ToString())
{
ValidationResult result = base.IsValid(value, context);
return result;
}
return ValidationResult.Success;
}
}
这里PropertyName是您要在其上设置条件的属性
DesiredValue是PropertyName(property)的特定值,您的其他属性必须针对该值进行必要的验证
假设你有以下几点
public class User
{
public UserType UserType { get; set; }
[RequiredIf("UserType", UserType.Admin, ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(ResourceString))]
public string Password
{
get;
set;
}
}
最后但并非最不重要的一点是,为您的属性注册适配器,以便它可以执行客户端验证(我将其放在global.asax中,Application_Start)
现在有了一个框架,可以立即执行此条件验证(以及其他方便的数据注释验证): 具体来说,请看一下[RequiredIfTrue(“IsSenior”)]验证器。您可以将其直接放在要验证的属性上,从而获得与“高级”属性关联的验证错误的所需行为
它可以作为一个NuGet软件包提供。我也有同样的问题,需要修改[Required]属性-根据http请求生成Required字段。该解决方案类似于Dan Hunex answer,但他的解决方案无法正常工作(请参阅注释)。我不使用不引人注目的验证,只使用现成的MicrosoftMvcValidation.js。 给你。实现自定义属性:
public class RequiredIfAttribute : RequiredAttribute
{
public RequiredIfAttribute(/*You can put here pararmeters if You need, as seen in other answers of this topic*/)
{
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
//You can put your logic here
return ValidationResult.Success;//I don't need its server-side so it always valid on server but you can do what you need
}
}
然后,您需要实现自定义提供程序,将其用作global.asax中的适配器
public class RequreIfValidator : DataAnnotationsModelValidator <RequiredIfAttribute>
{
ControllerContext ccontext;
public RequreIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute)
: base(metadata, context, attribute)
{
ccontext = context;// I need only http request
}
//override it for custom client-side validation
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
//here you can customize it as you want
ModelClientValidationRule rule = new ModelClientValidationRule()
{
ErrorMessage = ErrorMessage,
//and here is what i need on client side - if you want to make field required on client side just make ValidationType "required"
ValidationType =(ccontext.HttpContext.Request["extOperation"] == "2") ? "required" : "none";
};
return new ModelClientValidationRule[] { rule };
}
}
在这里
[RequiredIf]
public string NomenclatureId { get; set; }
对我来说,主要的优势是,我不必像在不引人注目的验证中那样编写自定义客户机验证程序。它的工作原理与[所需的]相同,但仅适用于您需要的情况。从模型状态有条件地删除错误的典型用法:
public ActionResult MyAction(MyViewModel vm)
{
// perform conditional test
// if true, then remove from ModelState (e.g. ModelState.Remove("MyKey")
// Do typical model state validation, inside following if:
// if (!ModelState.IsValid)
// Do rest of logic (e.g. fetching, saving
在您的示例中,保持一切原样,并将建议的逻辑添加到控制器的操作中。我假设您的ViewModel传递给controller操作,其中包含Person和Senior Person对象,其中包含从UI填充的数据。我一直在使用这个惊人的nuget,它可以进行动态注释 您可以验证您梦寐以求的任何逻辑:
public string Email { get; set; }
public string Phone { get; set; }
[RequiredIf("Email != null")]
[RequiredIf("Phone != null")]
[AssertThat("AgreeToContact == true")]
public bool? AgreeToContact { get; set; }
我使用的是MVC 5,但您可以尝试以下方式:
public DateTime JobStart { get; set; }
[AssertThat("StartDate >= JobStart", ErrorMessage = "Time Manager may not begin before job start date")]
[DisplayName("Start Date")]
[Required]
public DateTime? StartDate { get; set; }
在你的情况下,你会说“我
public ActionResult MyAction(MyViewModel vm)
{
// perform conditional test
// if true, then remove from ModelState (e.g. ModelState.Remove("MyKey")
// Do typical model state validation, inside following if:
// if (!ModelState.IsValid)
// Do rest of logic (e.g. fetching, saving
public string Email { get; set; }
public string Phone { get; set; }
[RequiredIf("Email != null")]
[RequiredIf("Phone != null")]
[AssertThat("AgreeToContact == true")]
public bool? AgreeToContact { get; set; }
public DateTime JobStart { get; set; }
[AssertThat("StartDate >= JobStart", ErrorMessage = "Time Manager may not begin before job start date")]
[DisplayName("Start Date")]
[Required]
public DateTime? StartDate { get; set; }