What’s a good way to validate a model when information external to the model is required in order for the validation to take place? For example, consider the following model:
public class Rating {
public string Comment { get; set; }
public int RatingLevel { get; set; }
}
The system administrator can then set the RatingLevels for which a comment is required. These settings are available through a settings service.
So, in order to fully validate the model I need information external to it, in this case the settings service.
I’ve considered the following so far:
- Inject the service into the model. The DefaultModelBinder uses System.Activator to create the object so it doesn’t go through the normal dependency resolver and I can’t inject the service into the model without creating a new model binder (besides which, that doesn’t feel like the correct way to go about it).
- Inject the service into an annotation. I’m not yet sure this is possible but will investigate further soon. It still feels clumsy.
- Use a custom model binder. Apparently I can implement OnPropertyValidating to do custom property validation. This seems the most preferable so far though I’m not yet sure how to do it.
Which method, above or not, is best suited to this type of validation problem?
Option 1 doesn’t fit. The only way it would work would be to pull in the dependency via the service locator anti-pattern.
Option 2
doesn’t work. Although I couldn’t see how this was possible because of the C# attribute requirements, it is possible. See the following for references:Option 3: I didn’t know about this earlier, but what appears to be a very powerful way to write validators is to use the ModelValidator class and a corresponding ModelValidatorProvider.
First, you create your custom ModelValidatorProvider:
ASP.NET MVC’s IDependencyResolver will attempt to resolve the above provider, so as long as it’s registered with your IoC container you won’t need to do anything else. And then the ModelValidator:
As the provider is retrieved through the
IDependencyResolverand the provider has full control over the returnedModelValidators I was easily able to inject the dependencies and perform necessary validation.