16

I'm building a Custom Validation Attribute in ASP.NET Core WebAPI. I need to access IDataProtector in my validator and another service I'm using to access the database. I've searched and wasn't ab;e to find any documentation for this. ActionFilters have the option of using ServiceFilter but there doesn't seem to be any option for Validation Attribute. Any ideas?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Madhav Shenoy
  • 798
  • 12
  • 32
  • 1
    You should not inject dependencies into attributes as expressed [here](https://stackoverflow.com/a/29916075/264697), [here](http://blog.ploeh.dk/2014/06/13/passive-attributes/) and [here](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=97). – Steven Sep 26 '16 at 17:06

4 Answers4

31

Use the GetService() method of the ValidationContext to get your database. i.e.

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
  MyDbContext db = (MyDbContext) validationContext.GetService(typeof(MyDbContext));
  //...
}
Richard
  • 311
  • 3
  • 4
  • 5
    And because the `ValidationContext` implements `IServiceProvider`, adding `using Microsoft.Extensions.DependencyInjection` will add the rest of the useful extensions to allow `validationContext.GetService()` without explicit casting. – Stoyan Dimov Nov 02 '18 at 09:59
  • Where does GetSerivce fetch the dependency from ? – Frank Q. Mar 26 '19 at 22:48
4

You can override IsValid method and use validationContext to resolve dependency:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)  
{
    var service = (IExternalService) validationContext.GetService(typeof(IExternalService));
    // use service
}
alireza.salemian
  • 536
  • 5
  • 21
  • that's somehow, isn't cool, it returns 400 HTTP error, instead of going through controller, ModelState.IsValid(), I need to access the bool returning one, that microsoft used to override in required and etc... – Hassan Faghihi Oct 03 '20 at 10:44
2

We had a similar requirement where additional data was needed to be passed to an attribute to provide enough context for it to perform the validation.

We came up with a way to build up a context object which could be passed to attributes. I blogged about it here.

We are using the async api to perform data access which presented some additional challenges.

Ross Jones
  • 973
  • 7
  • 20
0

Because validation attributes are typically defined on properties, they can't receive a reference via the constructor. At best if you did really deep into model binding, there may be something to customize to allow property injection, but most practically I just get a reference to the dependency resolver in the Validate method, and call the appropriate method.

Brian Mains
  • 50,520
  • 35
  • 148
  • 257