Inject service into Action Filter
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.
How to use Action Filters with Dependency Injection in ASP.NET CORE?
If you want to avoid the Service Locator pattern you can use DI by constructor injection with a TypeFilter
.
In your controller use
[TypeFilter(typeof(MyActionFilterAttribute), Arguments = new object[] {10})]
public IActionResult() NiceAction
{
...
}
And your ActionFilterAttribute
does not need to access a service provider instance anymore.
public class MyActionFilterAttribute : ActionFilterAttribute
{
public int Limit { get; set; } // some custom parameters passed from Action
private ICustomService CustomService { get; } // this must be resolved
public MyActionFilterAttribute(ICustomService service, int limit)
{
CustomService = service;
Limit = limit;
}
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await next();
}
}
For me the annotation [TypeFilter(typeof(MyActionFilterAttribute), Arguments = new object[] {10})]
seems to be awkward. In order to get a more readable annotation like [MyActionFilter(Limit = 10)]
your filter has to inherit from TypeFilterAttribute
. My answer of How do I add a parameter to an action filter in asp.net? shows an example for this approach.
Inject service into Action Filter with Autofac KeyFilterAttibute
You need to make sure that IService
and any other dependencies of the action filter are registered as well.
public IServiceProvider ConfigureServices(IServiceCollection services) {
//...
// Autofac
services.AddAutofac();
var builder = new ContainerBuilder();
//core integration
builder.Populate(services);
// Register the components getting filtered with keys
builder.RegisterType<Service1>().Keyed<IService>("test1");
builder.RegisterType<Service2>().Keyed<IService>("test2");
// Attach the filtering behavior to the component with the constructor
builder.RegisterType<CustomActionFilter>().WithAttributeFiltering();
var container = builder.Build();
var serviceProvider = new AutofacServiceProvider(container);
return serviceProvider;
}
Custom filters are added to the controller method and the controller class using the ServiceFilter
attribute like so:
[ServiceFilter(typeof(CustomActionFilter))]
[Route("api/custom")]
public class CustomController : Controller {
// GET: api/issues
[HttpGet]
[ServiceFilter(typeof(CustomActionFilter))]
public IActionResult Get() {
//...
}
}
Or you could have registered it globally in ConfigureServices
like
public void ConfigureServices(IServiceCollection services) {
services.AddMvc(options => {
options.Filters.Add(typeof(CustomActionFilter)); // by type
});
//...
}
Reference Filters : Dependency injection
Reference AutoFac : KeyFilterAttribute Class
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
How to inject service into custom ActionFilterAttribute (Web API)?
Almost everything is fine with the your code, but you should register your filter and service in another way.
In Asp Net Core WebAPI there several ways you can register your filter:
- Globally - for all controllers, actions, and Razor Pages. More information in Microsoft documentation
- For only one controller/method. More information in Microsoft documentation
Example of global registration:
services.AddControllers(options =>
{
options.Filters.Add(typeof(LoggerFilterAttribute));
});
Example of method registration in Controller:
I want notice - in this case you should use ServiceFilter
- this helps DI resolve any dependecines for your filter.
[HttpGet]
[ServiceFilter(typeof(LoggerFilterAttribute))]
public IEnumerable<WeatherForecast> Get()
{
}
This is my simple example for this task:
- My
SimpleService
public interface ISimpleService
{
void Notify(string text);
}
public class SimpleService : ISimpleService
{
public void Notify(string text)
{
Console.WriteLine($"Notify from {nameof(SimpleService)}. {text}");
}
}
ActionFilterAttribute
public class LoggerFilterAttribute : ActionFilterAttribute
{
private readonly ISimpleService _simpleService;
public LoggerFilterAttribute(ISimpleService simpleService)
{
_simpleService = simpleService;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
_simpleService.Notify($"Method {nameof(OnActionExecuting)}");
}
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
_simpleService.Notify($"Method {nameof(OnActionExecutionAsync)}");
return base.OnActionExecutionAsync(context, next);
}
}
- The main step - you should choose way of registration, because there is main difference between global registration and per controller/method in code.
- If you want use this way of registration - you need only register global filter and this is enough. All magic will be do by
WebAPI
with DI registration.
services.AddControllers(options =>
{
options.Filters.Add(typeof(LoggerFilterAttribute));
});
- If you want use registration per controller/method. You need to register your filter in DI. Because without it you will have Exception.
services.AddScoped<LoggerFilterAttribute>();
[HttpGet]
[ServiceFilter(typeof(LoggerFilterAttribute))]
public IEnumerable<WeatherForecast> Get()
{
}
- The last step register my service
services.AddTransient<ISimpleService, SimpleService>();
- Results
Injecting Repository into ActionFilter
You need to add ISqlRepository
to your services:
services.AddScoped<ISqlRepository,SqlRepository>();
The reason the sample project referenced did not have to do this is because ILoggerFactory
is added via the framework.
Related Topics
Windows.Forms.Timer or System.Threading.Timer
How to Post Data Using Httpclient
Loading Multiple Versions of the Same Assembly
Removing Nodes from an Xmldocument
How to Have an Enum Bound Combobox with Custom String Formatting for Enum Values
How to Specify Proxy Credentials in Your Web.Config
Setting/Getting the Class Properties by String Name
What Is Point of Ssl If Fiddler 2 Can Decrypt All Calls Over Https
How to Return Anonymous Type from Method
"Updatesourcetrigger=Propertychanged" Equivalent for a Windows Phone 7 Textbox
Built in .Net Algorithm to Round Value to the Nearest 10 Interval
How to Protect Resources That May Be Used in a Multi-Threaded or Async Environment
Is There a Generic Constraint I Could Use for the + Operator
Could Not Load File or Assembly ... the Parameter Is Incorrect
Correct Way Communicate Wsse Usernametoken for Soap Webservice