With ASP.NET MVC, is it possible to use constructor injection with the data annotation attributes (specifically, I'm using validation attributes)?
What I would like to be able to do is:
public class NoEmailTakenAttribute : ValidationAttribute
{
public NoEmailTakenAttribute(IService service) { .. }
}
Is that possible?
Thanks.
You can't use Controller injection from what I see using Reflector, but it does appear possible to use property injection. By creating a class that inherits from DataAnnotationsModelValidatorProvider, and by overriding the method GetValidators, it seems plausible that the attributes can be property injected into before the validation happens... this is from an initial analysis, yet to be fully determined.
The solution proposed by Brian Mains should work fine. I don't think constructor injection is an option here but property injection will do the job. You can derive from ModelValidatorProvider and your implementation might look similiar to this:
public class MyModelValidatorProvider : ModelValidatorProvider
{
private IDiContainer _container;
public MyModelValidatorProvider(IDiContainer container)
{
_container = container;
}
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
List<ModelValidator> validators = new List<ModelValidator>();
PropertyInfo targetProperty = metadata.ContainerType.GetProperty(metadata.PropertyName);
if (targetProperty.GetCustomAttributes(false).Any(attr => attr.GetType() == typeof(NoEmailTakenAttribute)))
{
DataAnnotationsModelValidator<NoEmailTakenAttribute> validator = new DataAnnotationsModelValidator<NoEmailTakenAttribute>(
metadata, context, _container.Resolve<NoEmailTakenAttribute>());
validators.Add(validator);
}
return validators;
}
}
I did not look closely into the ModelMetadata and just used refelction to decide whether to return the validator or not but it probably can be done better.
Then in the Global.asax add the following:
ModelValidatorProviders.Providers.Add(new MyModelValidatorProvider(InstanceOfContainer));
and you should be good to go. The only problem here is that your validator will get created by the default mechanism as well. Obviously this will result in your validator not having the proper dependencies injected. I have no idea how to exclude a validator from default creation but if you properly check against null values inside your validator it should work fine (a bit of a workaround i must say but maybe you'll find a better way).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With