tbonejenkins
tbonejenkins

Reputation: 379

Validating property value, based on another model property

I have a question regarding property validation, however, I haven't yet been able to find an appropriate answer.

I have the following classes

public class IndexViewModel
{
    public Film Film { get; set; }

    public ReviewModel Review { get; set; }
}

public class ReviewModel
{
    [RequiredIf // only fire if 'Genre' is equal to Genre.Horror]
    public string Text { get; set; }
}

public class Film
{
    public string Title { get; set; }
    public Director Director { get; set; }
    public Genre Genre { get; set; }
}

public class Director
{
    public string Name { get; set; }
}

public enum Genre
{
    Horror,
    Thriller,
    SciFi,
    Drama
}

Is it possible to add a [RequiredIf] attribute on the Text property in ReviewModel which fires validation based on the value of Genre in the Film model. Any Help would be greatly appreciated.

Upvotes: 1

Views: 1870

Answers (2)

dfdsfdsfsdf
dfdsfdsfsdf

Reputation: 663

Put it in your business layer.

[RequiredIf // only fire if 'Genre' is equal to Genre.Horror

]

if you need to put it on your model, you might as well implement

System.ComponentModel.IValidatableObject

and then use the ObjectValidator to validate it.

However based on experience, I do basic attribute decoration on my model such as Required and StringLength, so that asp.net MVC can pick up on, and dump the important business rule in my service layer, since the validation logic is rarely that simple and usually require external data elements like additional calls to the database.

it really depends on your use cases. I like to keep my data classes dumb because i expect the data to be moved around and thus the validation logic would be lost during serialization i.e JSON serialization.

Upvotes: 1

Will Ray
Will Ray

Reputation: 10879

I wouldn't recommend using validation attributes when the properties that need to be validated aren't in the class it's associated with. I haven't seen a RequiredIfAttribute implementation that cuts across models like that. (Here's a good one from a different question.)

What about a simple implementation of IValidatableObject? It would be quite clear, and MVC will check for it when constructing the model.

public class IndexViewModel : IValidatableObject
{
    public Film Film { get; set; }

    public ReviewModel Review { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Film.Genre == Genre.Horror && string.IsNullOrWhiteSpace(Review.Text))
        {
            yield return new ValidationResult(
                "Please provide a review for this film.",
                new string[] { nameof(Review.Text) });
        }
    }
}

Upvotes: 3

Related Questions