Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET MVC条件验证_C#_Asp.net Mvc_Forms_Validation - Fatal编程技术网

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; }

对我来说,主要的优势是,我不必像在不引人注目的验证中那样编写自定义客户机验证程序。它的工作原理与[所需的]相同,但仅适用于您需要的情况。

从模型状态有条件地删除错误的典型用法:

  • 使条件成为控制器操作的第一部分
  • 执行逻辑以从ModelState中删除错误
  • 执行现有逻辑的其余部分(通常是模型状态验证,然后是所有其他操作)
  • 例如:

    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; }