views:

162

answers:

1

I'm currently trying to work through MVC validation, and am coming up against some problems where a field is required depending on the value of another field. An example is below (that I haven't figured out yet) - If the PaymentMethod == "Cheque", then the ChequeName should be required, otherwise it can be let through.

[Required(ErrorMessage = "Payment Method must be selected")]
public override string PaymentMethod
{ get; set; }

[Required(ErrorMessage = "ChequeName is required")]
public override string ChequeName
{ get; set; }

I'm using the System.ComponentModel.DataAnnotations for the [Required], and have also extended a ValidationAttribute to try and get this working, but I can't pass a variable through to do the validation (extension below)

public class JEPaymentDetailRequired : ValidationAttribute 
{
    public string PaymentSelected { get; set; }
    public string PaymentType { get; set; }

    public override bool IsValid(object value)
    {
        if (PaymentSelected != PaymentType)
            return true;
        var stringDetail = (string) value;
        if (stringDetail.Length == 0)
            return false;
        return true;
    }
}

Implementation:

[JEPaymentDetailRequired(PaymentSelected = PaymentMethod, PaymentType = "Cheque", ErrorMessage = "Cheque name must be completed when payment type of cheque")]

Has anyone had experience with this sort of validation? Would it just be better to write it into the controller?

Thanks for your help.

+1  A: 

I would write the validation logic in the model, not the controller. The controller should only handle interaction between the view and the model. Since it's the model that requires validation, I think it's widely regarded as the place for validation logic.

For validation that depends on the value of another property or field, I (unfortunately) don't see how to completely avoid writing some code for that in the model, such as shown in the Wrox ASP.NET MVC book, sort of like:

public bool IsValid
{
  get 
  {
    SetRuleViolations();
    return (RuleViolations.Count == 0); 
  }
}

public void SetRuleViolations()
{
  if (this.PaymentMethod == "Cheque" && String.IsNullOrEmpty(this.ChequeName))
  {
    RuleViolations.Add("Cheque name is required", "ChequeName");
  }
}

Doing all validation declaratively would be great. I'm sure you could make a RequiredDependentAttribute, but that would only handle this one type of logic. Stuff that is even slightly more complex would require yet another pretty specific attribute, etc. which gets crazy quickly.

djuth
thanks djuth, I've taken a ModelStateDictionary and done validation with this in the model, and then passed the dictionary back to the controller to merge into the ModelState. Seems to do the trick and allows me to do some programmatic work - not quite as nice just doing a declaration per attribute, but at least I can get everything in the one spot. Not sure how this will go if there's more than one error per attribute tho.
Sam J