8

I am writing attribute that will verify captcha. In order to work correctly it needs to know secret, which I keep in the settings (Secret manager tool). However I don't know how to read config from the attribute class. DI in asp.net core supports constructor injection (and property injection is not supported), so this will give compilation error:

public ValidateReCaptchaAttribute(IConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            this.m_configuration = configuration;
        }

because when I decorate method with [ValidateReCaptcha] I can't pass config

So how do I can read something from config from the method in attribute class?

vmg
  • 8,856
  • 12
  • 55
  • 83

2 Answers2

13

You can use ServiceFilter attribute, more info in this blog post and asp.net docs.

[ServiceFilter(typeof(ValidateReCaptchaAttribute))]
public IActionResult SomeAction()

In Startup

public void ConfigureServices(IServiceCollection services)
{
       // Add functionality to inject IOptions<T>
       services.AddOptions();

       // Add our Config object so it can be injected
       services.Configure<CaptchaSettings>(Configuration.GetSection("CaptchaSettings"));

       services.AddScoped<ValidateReCaptchaAttribute>();
       ...
}

And ValidateReCaptchaAttribute

public class ValidateReCaptchaAttribute : ActionFilterAttribute
{
     private readonly CaptchaSettings _settings;

     public ValidateReCaptchaAttribute(IOptions<CaptchaSettings> options)
     {
         _settings = options.Value;
     }

     public override void OnActionExecuting(ActionExecutingContext context)
     {
         ...
         base.OnActionExecuting(context);
     }
}
tmg
  • 17,493
  • 5
  • 61
  • 69
  • Where does IOptions come from? Is that necessary? It's not mentioned in either of the docs you linked. – starmandeluxe Apr 28 '17 at 08:27
  • @starmandeluxe This mechanism allows to inject strong typed options into services. You can find more info at Rick Strahl's [post](https://weblog.west-wind.com/posts/2016/may/23/strongly-typed-configuration-settings-in-aspnet-core) – tmg Apr 28 '17 at 08:53
  • Thank you! Unfortunately it doesn't work for me this way. It requires a parameterless constructor in the config object, and inside mine I need to grab settings from appSettings.json, which requires a IConfigurationRoot parameter. The result is that all the fields are null since it seems like it's not using my parameterized constructor. – starmandeluxe Apr 28 '17 at 09:11
  • @starmandeluxe I am not able to understand your issue. Its better if you make a new post – tmg Apr 28 '17 at 09:26
  • I figured it out. It requires to first use services.AddSingleton() to initialize the config instead of services.Configure() – starmandeluxe Apr 28 '17 at 09:53
5

You should use ServiceFilter like this:

[ServiceFilter(typeof(ValidateReCaptcha))]

And if you want to use IConfiguration you should inject it in ConfigureServices:

services.AddSingleton((provider)=>
{
     return Configuration;
});
adem caglin
  • 17,749
  • 8
  • 44
  • 67