Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use dependency injection with an attribute?

In an MVC project I'm creating I have the following RequirePermissionAttribute that gets put on any action that needs specific permissions (it's been simplified for this example):

public class RequirePermissionAttribute : ActionFilterAttribute, IAuthorizationFilter {     public Operation Permissions { get; set; }      public RequirePermissionAttribute() { }      public RequirePermissionAttribute(Operation permissions)     {         this.Permissions = permissions;     }      public bool AuthorizeCore(HttpContextBase httpContext)     {         IAuthorizationService authServ = new ASPNETAuthorizationService();         return authServ.Authorize(httpContext);     }      public void OnAuthorization(AuthorizationContext filterContext)     {         Enforce.ArgNotNull(filterContext);          if (this.AuthorizeCore(filterContext.HttpContext))         {             // code snipped.         }         else         {             // code snipped.         }     } } 

So the problem obviously with this is that my authorize attribute has a dependency on the ASPNETAuthorizationService that I created. I can't go the constructor way since attributes are compile-time checked.

One thing to mention, I'm using my own little IoC that I made and it doesn't have support for property injection (yet). Of course, if I did go the property injection route, I'd have to add support for it (which I'd have to do some research on).

What's the best way to inject something into an attribute class?

like image 399
TheCloudlessSky Avatar asked Nov 04 '10 22:11

TheCloudlessSky


People also ask

How do C# attributes work?

In C#, attributes are classes that inherit from the Attribute base class. Any class that inherits from Attribute can be used as a sort of "tag" on other pieces of code. For instance, there is an attribute called ObsoleteAttribute . This is used to signal that code is obsolete and shouldn't be used anymore.

What is dependency attribute?

The ability for some attributes to control the behavior of other attributes is known as attribute dependency. An attribute dependency rule defines the effect that a source attribute value has on one or more target attribute values.

How do you perform a dependency injection?

Types of Dependency Injection The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through a method. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.

What is dependency injection with example?

Dependency injection (DI) is a technique widely used in programming and well suited to Android development. By following the principles of DI, you lay the groundwork for good app architecture. Implementing dependency injection provides you with the following advantages: Reusability of code.


1 Answers

What's the best way to inject something into an attribute class?

Strictly speaking, we cannot use dependency injection to inject a dependency into an attribute. Attributes are for metadata not behavior. [AttributeSpecification()] encourages this by forbidding reference types as arguments.

What you're probably looking for is to use an attribute and a filter together, and then to inject dependencies into the filter. The attribute adds metadata, which determines whether to apply the filter, and the filter receives the injected dependencies.

How to use dependency injection with an attribute?

There are very few reasons to do this.

That said, if you're intent on injecting into an attribute, you can use the ASP.NET Core MVC IApplicationModelProvider. The framework passes dependencies into the provider's constructor, and the provider can pass dependencies to the attribute's properties or methods.

In your Startup, register your provider.

using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions;  public class Startup {     public void ConfigureServices(IServiceCollection services)     {         services.TryAddEnumerable(ServiceDescriptor.Transient             <IApplicationModelProvider, MyApplicationModelProvider>());          services.AddMvc();     }      public void Configure(IApplicationBuilder app)     {         app.UseMvc();     } } 

Use constructor injection in the provider, and pass those dependencies to the attribute.

using System.Linq; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.Routing;  public class MyApplicationModelProvider : IApplicationModelProvider {     private IUrlHelperFactory _urlHelperFactory;      // constructor injection     public MyApplicationModelProvider(IUrlHelperFactory urlHelperFactory)     {         _urlHelperFactory = urlHelperFactory;     }      public int Order { get { return -1000 + 10; } }      public void OnProvidersExecuted(ApplicationModelProviderContext context)     {         foreach (var controllerModel in context.Result.Controllers)         {             // pass the depencency to controller attibutes             controllerModel.Attributes                 .OfType<MyAttribute>().ToList()                 .ForEach(a => a.UrlHelperFactory = _urlHelperFactory);              // pass the dependency to action attributes             controllerModel.Actions.SelectMany(a => a.Attributes)                 .OfType<MyAttribute>().ToList()                 .ForEach(a => a.UrlHelperFactory = _urlHelperFactory);         }     }      public void OnProvidersExecuting(ApplicationModelProviderContext context)     {         // intentionally empty     } } 

Create an attribute with public setters that can receive dependencies.

using System; using Microsoft.AspNetCore.Mvc.Routing;  public sealed class MyAttribute : Attribute {     private string _someParameter;      public IUrlHelperFactory UrlHelperFactory { get; set; }      public MyAttribute(string someParameter)     {         _someParameter = someParameter;     } } 

Apply the attribute to a controller or an action.

using Microsoft.AspNetCore.Mvc;  [Route("api/[controller]")] [MyAttribute("SomeArgument")] public class ValuesController : Controller {     [HttpGet]     [MyAttribute("AnotherArgument")]     public string Get()     {         return "Foobar";     } } 

The above demonstrates one way, for the rare use case, that you can inject dependencies into an attribute. If you figure out a valid reason to do this, please post it in the comments.

like image 78
Shaun Luttin Avatar answered Sep 19 '22 20:09

Shaun Luttin