我有一个类似的地址类:
public class CustomerAddress
{
[Required]
public string Line1 { get; set; }
public string Line2 { get; set; }
[Required]
public string Town { get; set; }
[Required]
public string Postcode { get; set; }
}
我有一个像这样的视图模型:
public class CheckoutViewModel
{
[Required]
public string Name { get; set; }
//... etc
public bool DeliverySameAsBilling { get; set; }
public CustomerAddress BillingAddress { get; set; }
public CustomerAddress DeliveryAddress { get; set; }
}
我只希望在DeliverySameAsBilling
为假时验证传递地址,我可以从this看到IValidatableObject可能是最佳选择。
该示例对模型施加了比属性更严格的标准;在我的情况下,我想要选择忽略[Required]
类中的CustomerAddress
属性。我该怎么做呢?我如何连接适当的客户端验证?
或者,我可以在BillingAddress
和DeliveryAddress
的每一个上使用this等自定义属性,然后可能更容易处理客户端验证;但是,如果DeliverySameAsBilling
为真,我仍然不知道如何有效地“取消”该属性的验证。
哪个最好?
答案 0 :(得分:3)
看看这个。
http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx
创建RequiredIfAttribute
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace ConditionalValidation.Validation
{
public class RequiredIfAttribute : ValidationAttribute
{
// Note: we don't inherit from RequiredAttribute as some elements of the MVC
// framework specifically look for it and choose not to add a RequiredValidator
// for non-nullable fields if one is found. This would be invalid if we inherited
// from it as obviously our RequiredIf only applies if a condition is satisfied.
// Therefore we're using a private instance of one just so we can reuse the IsValid
// logic, and don't need to rewrite it.
private RequiredAttribute innerAttribute = new RequiredAttribute();
public string DependentProperty { get; set; }
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue)
{
this.DependentProperty = dependentProperty;
this.TargetValue = targetValue;
}
public override bool IsValid(object value)
{
return innerAttribute.IsValid(value);
}
}
}
然后创建一个RequiredIfValidator
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ConditionalValidation.Validation
{
public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute>
{
public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute)
: base(metadata, context, attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
// no client validation - I might well blog about this soon!
return base.GetClientValidationRules();
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
// get a reference to the property this validation depends upon
var field = Metadata.ContainerType.GetProperty(Attribute.DependentProperty);
if (field != null)
{
// get the value of the dependent property
var value = field.GetValue(container, null);
// compare the value against the target value
if ((value == null && Attribute.TargetValue == null) ||
(value.Equals(Attribute.TargetValue)))
{
// match => means we should try validating this field
if (!Attribute.IsValid(Metadata.Model))
// validation failed - return an error
yield return new ModelValidationResult { Message = ErrorMessage };
}
}
}
}
}
并在模型中使用它
namespace ConditionalValidation.Models
{
public class Person
{
[HiddenInput(DisplayValue = false)]
public int Id { get; set; }
[StringLength(10)]
[RequiredIf("City", null)]
public string Name { get; set; }
[RequiredIf("IsUKResident", true, ErrorMessage = "You must specify the City if UK resident")]
public string City { get; set; }
[RequiredIf("IsUKResident", false, ErrorMessage = "You must specify the country if not UK resident")]
[RegularExpression("^(\\w)+$", ErrorMessage = "Only letters are permitted in the Country field")]
public string Country { get; set; }
// this field is last in the class - therefore any RequiredAttribute validation that occurs
// on fields before it don't guarantee this field's value is correctly set - see my blog post
// if that doesn't make sense!
[DisplayName("UK Resident")]
public bool IsUKResident { get; set; }
}
}