Выборочная проверка в MVC3 - PullRequest
1 голос
/ 26 октября 2011

У меня есть класс адресов, подобный следующему:

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имеет значение false, и из this я вижу, что IValidatableObject может быть подходящим способом.

Этот пример налагает на модель более строгие критерии, чем атрибуты;в моем случае я хочу дополнительно игнорировать атрибуты [Required] в классе CustomerAddress.Как мне это сделать?Как бы я подключил соответствующую проверку на стороне клиента?

В качестве альтернативы я мог бы использовать пользовательский атрибут, такой как this для каждого из BillingAddress и DeliveryAddress, а затем, возможно, проверка на стороне клиента могла быбыть более легким в обращении;однако я все еще не знаю, как эффективно «отменить» проверку свойства, если DeliverySameAsBilling истинно.

Что лучше?

1 Ответ

3 голосов
/ 26 октября 2011

Взгляните на это.

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; }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...