Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject service into Action Filter

I am trying to inject a service into my action filter but I am not getting the required service injected in the constructor. Here is what I have:

public class EnsureUserLoggedIn : ActionFilterAttribute {     private readonly ISessionService _sessionService;      public EnsureUserLoggedIn()     {         // I was unable able to remove the default ctor          // because of compilation error while using the          // attribute in my controller     }      public EnsureUserLoggedIn(ISessionService sessionService)     {         _sessionService = sessionService;     }      public override void OnActionExecuting(ActionExecutingContext context)     {         // Problem: _sessionService is null here         if (_sessionService.LoggedInUser == null)         {             context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;             context.Result = new JsonResult("Unauthorized");         }     } } 

And I am decorating my controller like so:

[Route("api/issues"), EnsureUserLoggedIn] public class IssueController : Controller { } 

Startup.cs

services.AddScoped<ISessionService, SessionService>(); 
like image 219
hyde Avatar asked Mar 20 '16 00:03

hyde


People also ask

How do you implement an action filter?

You can create a custom action filter in two ways, first, by implementing the IActionFilter interface and the FilterAttribute class. Second, by deriving the ActionFilterAttribute abstract class.

What is TypeFilterAttribute?

TypeFilterAttribute. TypeFilterAttribute is similar to ServiceFilterAttribute, but its type isn't resolved directly from the DI container. It instantiates the type by using Microsoft. Extensions.

Does Net Web API support action filter?

Web API includes filters to add extra logic before or after action method executes. Filters can be used to provide cross-cutting features such as logging, exception handling, performance measurement, authentication and authorization.

How to inject components into action filters?

Injecting components into action filter attributes directly is not possible but there are various workarounds to allow us to effectively accomplish the same thing. Using ServiceFilter is a relatively clean way to allow dependency injection into individual action filters.

Is it possible to inject dependencies into an action filter attribute?

Sometimes these filters need to use other components but attributes are quite limited in their functionality and dependency injection into an attribute is not directly possible. This post looks at a few different techniques for injecting dependencies into action filters in ASP.NET Core.

Can servicefilter be used for dependency injection?

Using ServiceFilter is a relatively clean way to allow dependency injection into individual action filters. Specifying the type for the filter this way does mean that invalid types can be entered and will not be discovered until runtime however.

Can dependency injection be used in MVC controller actions?

It is quite common to decorate ASP.NET MVC controller actions with filter attributes to separate cross cutting concerns from the main concern of the action. Sometimes these filters need to use other components but attributes are quite limited in their functionality and dependency injection into an attribute is not directly possible.


2 Answers

Using these articles as reference:

ASP.NET Core Action Filters

Action filters, service filters and type filters in ASP.NET 5 and MVC 6

Using the filter as a ServiceFilter

Because the filter will be used as a ServiceType, it needs to be registered with the framework IoC. If the action filters were used directly, this would not be required.

Startup.cs

public void ConfigureServices(IServiceCollection services) {     services.AddMvc();      services.AddScoped<ISessionService, SessionService>();     services.AddScoped<EnsureUserLoggedIn>();      ... } 

Custom filters are added to the MVC controller method and the controller class using the ServiceFilter attribute like so:

[ServiceFilter(typeof(EnsureUserLoggedIn))] [Route("api/issues")] public class IssueController : Controller {     // GET: api/issues     [HttpGet]     [ServiceFilter(typeof(EnsureUserLoggedIn))]     public IEnumerable<string> Get(){...} } 

There were other examples of

  • Using the filter as a global filter

  • Using the filter with base controllers

  • Using the filter with an order

Take a look, give them a try and see if that resolves your issue.

Hope this helps.

like image 71
Nkosi Avatar answered Sep 23 '22 21:09

Nkosi


Global filters

You need to implement IFilterFactory:

public class AuthorizationFilterFactory : IFilterFactory {     public bool IsReusable => false;      public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)     {         // manually find and inject necessary dependencies.         var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext));         return new AuthorizationFilter(context);     } } 

In Startup class instead of registering an actual filter you register your filter factory:

services.AddMvc(options => {     options.Filters.Add(new AuthorizationFilterFactory()); }); 
like image 43
Andrei Avatar answered Sep 24 '22 21:09

Andrei