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>();
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.
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());
});
One more way for resolving this problem. You can get your service via Context as in the following code:
public override void OnActionExecuting(ActionExecutingContext context)
{
_sessionService = context.HttpContext.RequestServices.GetService<ISessionService>();
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
Please note that you have to register this service in Startup.cs
services.AddTransient<ISessionService, SessionService>();
Example
private ILoginService _loginService;
public override void OnActionExecuting(ActionExecutingContext context)
{
_loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
}
Hope it helps.