Dependency Injection in Attributes

Dependency injection in custom attribute

Firstly,you need inject IHttpContextAccessor instead of HttpContextAccessor.

Secondly,service is not a valid attribute parameter type.I suggest that you could use ActionFilterAttribute or any other Attribute(It depends on your detailed scenario) which could cast to ServiceFilterAttribute or TypeFilterAttribute.

Here is a whole working demo:

Custom ActionFilterAttribute:

public class MyAttribute : ActionFilterAttribute
{
private readonly IHttpContextAccessor _accessor;
private readonly IUserService _userService;


public MyAttribute(IHttpContextAccessor accessor, IUserService userService)
{
_accessor = accessor;
_userService = userService;
}
}

Controller:

//[ServiceFilter(typeof(MyAttribute))]
[TypeFilter(typeof(MyAttribute))]
public async Task<IActionResult> Index()
{
return View();
}

Register services:

public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddScoped<IUserService, UserService>();
services.AddScoped<MyAttribute>();
}

Reference:

get values from class and method attribute in middleware in asp.net core

Dependency Injection in attributes

You should prevent doing dependency injection into attributes completely. The reason for this is explained in this article: Dependency Injection in Attributes: don’t do it!. In summary the article explains that:

  • Constructor injection is not possible, because creation of an Attribute instance cannot be intercepted; the CLR is in control.
  • The use of property injection is fragile, since it results in Temporal Coupling, which should be prevented.
  • Dependency injection into attributes makes it impossible to verify
    the correctness of the container's configuration.
  • Frameworks like MVC and Web API cache attributes, making it very easy to accidentally create captive dependencies causing bugs.

You have two choices here:

  1. Make the attributes passive, by splitting the data (the attribute) from its behavior (the service) as explained in the referenced article and this related article from Mark Seemann.
  2. Turn your attributes into humble objects as explained in this answer. This means you:

    1. extract all logic from the attribute into a custom service that contains all dependencies.
    2. Register that service in your container.
    3. let the attribute's method (AuthorizeCore in your case) do nothing more than resolving the service from the service locator / DependencyResolver and call the service's method. Important to note here is that you cannot do constructor injection, property injection and the service cannot be stored in the attributes private state (as you already noticed).

Which option to use:

  • Use option 1 if you are very keen into keeping your design clean, or you have more than a few attributes that you need to apply this way, or you want to apply attributes are defined in an assembly that doesn't depend on System.Web.Mvc.
  • Use option 2 otherwise.

C# ASP.NET Core [Inject] Attribute Usage for Dependency Injection

The [Inject] attribute is solely applied to Blazor Components. Property injection will not be applied to registrations made to the IServiceCollection, even if you mark those properties with [Inject]. The built-in DI Container is not capable of applying property injection.

The sole reason for the existence of the InjectAttribute is to use the @inject tag in Razor pages. When you use the @inject tag, Blazor will generate a public property on your Blazor Component that is marked with [Inject].

Although Property Injection is described as a valid pattern for practicing DI in DIPP&P (section 4.4), the book also warns about the downsides of Property Injection, and the authors (Mark Seemann and I) state that:

When building applications [...] we never use Property Injection, and you should do so sparingly. Even though you might have a Local Default for a Dependency, Constructor Injection still provides you with a better alternative. Constructor Injection is simpler and more robust. You might think you need Property Injection to work around a cyclic Dependency, but that’s a code smell, as we’ll explain in chapter 6.

So, whenever possible, refrain from using Property Injection and use Constructor Injection as your sole way to provide dependencies to a consumer.

How can I use Dependency Injection in a .Net Core ActionFilterAttribute?

Instead of resolving at construction, ActionExecutingContext.HttpContext.RequestServices should give you a reference to the request's service container at the time of the request.

So:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var svc = filterContext.HttpContext.RequestServices;
var memCache = svc.GetService<IMemoryCache>();
//..etc

Custom filter attributes inject dependency

If anyone finds similar issue here's how I manage to solve it.

My custom filter inherits IAutofacAuthorizationFilter. Besides this one you can also inherit IAutofacExceptionFilter and IAutofacActionFilter.
And inside my DI container I've register this filter for each controller I want to use like this

        builder.Register(c => new CustomAuthorizationAttribute(c.Resolve<IAccountBL>()))
.AsWebApiAuthorizationFilterFor<MemberController>()
.InstancePerApiRequest();

dependency injection: Which one should be made first? attributes(fields) or dependency?


I think first we create the attribute

I think you might be confusing OOP concepts with injection.

You Car service class (nothing to do with OOP), need access to the Tires service class, so the Car instance expects a Tires instance to be injected during construction, and it needs to save that for later use, so it stores the reference in a field (not attribute1).

The field is defined (declared, "created") when we decide that we need to save the injected reference for later.

I guess you could say we define ("create") the field when we realize we need a reference to the Tire service, and then go add it as a dependency to the constructor, but that's just semantic about when you write the code, i.e. whether you look ahead and create the dependency before you write the code that needs it, or you create the dependencies on-the-fly as you write the code.

1) The word "attribute" is used when we have getter (and setter) methods for an external class to use. An injected reference, for internal use only, is not considered to be a "attribute" of the class.

How can I both dependency injection and send value inside the attribute in .net core?

If you want to get the service inside the filter attribute, you could use service location to resolve components from the built-in IoC container by using RequestServices.GetService.

More details, you could refer to below codes:

public class ThrottleFilterAttribute : Attribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
var cache = context.HttpContext.RequestServices.GetService<IDistributedCache>();
...
}
...
}


Related Topics



Leave a reply



Submit