문제

Using Nhibernate Validator (with S#harp Architecture / MVC3), how can I write a custom attribute, preferably not object-specific (since this is a fairly common requirement) that enforces that PropertyA >= PropertyB (or in the more general case, both may be null).

Something like

public DateTime? StartDate { get; set; }

[GreaterThanOrEqual("StartDate")]
public DateTime? EndDate { get; set; }

I see that I can override IsValid in the particular Entity class but I wasn't sure if that was the best approach, and I didn't see how to provide a message in that case.

도움이 되었습니까?

해결책

When you need to compare multiple properties of an object as part of validation, you need a claass validator. The attribute is then applied to the class, not the property.

I don't think there is an existing one to do what you want, but it is easy enough to write your own.

Here is a code outline to show you roughly what your validator could look like

[AttributeUsage(AttributeTargets.Class)]
[ValidatorClass(typeof(ReferencedByValidator))]
public class GreaterThanOrEqualAttribute : EmbeddedRuleArgsAttribute, IRuleArgs
{        
    public GreaterThanOrEqualAttribute(string firstProperty, string secondProperty)
    {
        /// Set Properties etc
    }
}

public class ReferencedByValidator : IInitializableValidator<GreaterThanOrEqualAttribute>
{       
    #region IInitializableValidator<ReferencedByAttribute> Members

    public void Initialize(GreaterThanOrEqualAttribute parameters)
    {
        this.firstProperty = parameters.FirstProperty;
        this.secondProperty = parameters.SecondProperty;
    }

    #endregion

    #region IValidator Members

    public bool IsValid(object value, IConstraintValidatorContext constraintContext)
    {
       // value is the object you are trying to validate

        // some reflection code goes here to compare the two specified properties
   }
    #endregion

}

}

다른 팁

Currently, if I need to do this on a model, I have the model implement IValidatableObject

public class DateRangeModel : IValidatableObject {

   public DateTime StartDate { get; set; }
   public DateTime EndDate { get; set; }


   public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> results = new List<ValidationResult>();
        if (StartDate > EndDate)
        {
            results.Add(new ValidationResult("The Start Date cannot be before the End Date.", "StartDate"));
        }
        return results;
    }

This seems to provide good integration with the existing system. The drawback is that since this is not applied on the domain object, you need additional logic there (or in a services layer that creates the domain objects, etc.) to enforce it from that end too, in case a different model is used elsewhere to create or update the domain objects.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top