Skip to content

Instantly share code, notes, and snippets.

@Oxyrus
Created May 28, 2024 19:08
Show Gist options
  • Save Oxyrus/d4a1a89509ca0d3d67afc74df9bbe335 to your computer and use it in GitHub Desktop.
Save Oxyrus/d4a1a89509ca0d3d67afc74df9bbe335 to your computer and use it in GitHub Desktop.

How to have dependency injection and parameters at the same time?

Recently I needed to have a custom authorization attribute to use in my .NET API, where I needed to have some dependency injected services but also pass in an argument to the attribute. I hope this can help you:

enum Feature
{
    Articles,
    Comments
}
public class CustomAuthorizeAttribute : TypeFilterAttribute
{
    // Instead of an enum you can use any other type you want, in my case I had a predefined
    // list of features I wanted to authorize against.
    public CustomAuthorizeAttribute(Feature feature) : base(typeof(CustomAuthorizeFilter))
    {
        Arguments = new object[] { feature };
    }
}

public class CustomAuthorizeFilter : IAuthorizationFilter
{
    private readonly IServiceA _serviceA;
    private readonly Feature _feature;
    
    public CustomAuthorizeFilter(Feature feature, IServiceA serviceA)
    {
        _feature = feature;
        _serviceA = serviceA;
    }
    
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        // Here the _feature passed in from the usage of the attribute will be available.
        // You can also use the service(s) you injected.
    }
}

Then we must register the required services for dependency injection.

builder.Services.AddScoped<IServiceA, ServiceA>();
builder.Services.AddScoped<CustomAuthorizeAttribute>();

Finally you can use the attribute in your controller(s).

[ApiController]
public class CommentsController : ControllerBase
{
    [CustomAuthorize(Feature.Comments)]
    [HttpPost]
    public async Task<IActionResult> AddComment()
    {
        // ...
    }
}

You can also specify a default value for your parameter so you don't have to pass one each time:

public class CustomAuthorizeAttribute : TypeFilterAttribute
{
    // Instead of an enum you can use any other type you want, in my case I had a predefined
    // list of features I wanted to authorize against.
    public CustomAuthorizeAttribute(Feature feature = Feature.Comments) : base(typeof(CustomAuthorizeFilter))
    {
        Arguments = new object[] { feature };
    }
}

[ApiController]
public class CommentsController : ControllerBase
{
    [CustomAuthorize]
    [HttpPost]
    public async Task<IActionResult> AddComment()
    {
        // ...
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment