问题
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.
回答1:
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.
回答2:
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).
回答3:
You can do this by creating base controller class and declare property for IService interface and write base controller class with parameter IService. Use this in your derived class. As asp.net mvc uses the default controller constructor to initialise that time your service get instantiated by derived class parameterized constructor.
回答4:
I don't think there is an easy way to do constructor injection or even property injection for custom data annotations. What @BrianMains suggested sounds plausible, but I haven't gone that far with it myself.
One way to get around the complexity is to use a service locator in the custom data annotation to get whichever dependency you need. Not as clean, but gets you the same result.
Check this link out for more info: Dependency injection in custom DataAnnotations in ASP.Net MVC 3
回答5:
Brian Mains answer is correct but bit too brief. So here is an example.
First define a provider
public class CustomProvider : DataAnnotationsModelValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, IEnumerable<ModelValidatorProvider> validatorProviders, IEnumerable<Attribute> attributes)
{
foreach (var attrib in attributes)
{
//if the attrib is your one set whatever you need
}
return base.GetValidators(metadata, validatorProviders, attributes);
}
}
and then register it - for MVC see dmusial answer. For Web Api(How To Add Custom ModelValidatorProviders To Web API Project? )
config.Services.Add(typeof(ModelValidatorProvider), new CustomProvider());
来源:https://stackoverflow.com/questions/13852428/data-annotations-constructor-injection