C# - Custom ActionFilter pass in configuration variables

1.1k Views Asked by At

I have a custom action filter that takes in a property but I need the property to come from my appsettings.json file. I pass my configuration into the controller, but when I try to pass in the "_config.GetValue< string >("myString")" the "_config" is red underlined with the message:

An object reference is required for the non-static field, method, or property 'MyController._config'

Action Filter

public class MyActionFilter : ActionFilterAttribute
{
    public string Property1 { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        ...
    }
}

Controller

[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
    private readonly IConfiguration _config;

    public MyController(IConfiguration config) {
        _config = config;
    }

    [Authorize]
    [HttpPost(Constants.ActionName.MyMethod, Name = nameof(MyMethod))]
    [MyActionFilter(Property1 = _config.GetValue<string>("myString"))] // Breaks here!
    public ActionResult<string> MyMethod()
    {
        ...
    }
}

How can I do this? Or at least, how can I avoid hardcoding a value for my action filter properties?

1

There are 1 best solutions below

0
kmschaal On

Your current approach does not work because constructor parameters and properties of attributes are evaluated at compile time.

You could use the service locator pattern in your filter like so:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var config = filterContext.HttpContext.RequestServices.GetService<IConfiguration>();
    string Property1 = config.GetValue<string>("myString");
}

However, this approach is debatable because the service locator pattern is considered an anti-pattern.

Another approach is to use a ServiceFilter. First, create a constructor for the action filter:

public MyActionFilter(string property1)
{
    Property1 = property1;
}

Second, change the action filter to a service filter in the controller:

[ServiceFilter(typeof(MyActionFilter))] 
public ActionResult<string> MyMethod()
{
    ...
}

Third, register the action filter:

builder.Services.AddScoped(p => new MyActionFilter(p.GetService<IConfiguration>().GetValue<string>("myString")));

Here is a great blogpost about the topic: Dependency Injection in action filters in ASP.NET Core.