1

I tried this answer: [https://stackoverflow.com/questions/18406506/custom-filter-attributes-inject-dependency][1] to implement ActionFilterAttribute (System.Web.Http.Filters) for Web API project (not MVC). But my custom attribute never called in controller. I would be grateful for any advice.

Custom attribute:

public class MyAttribute : FilterAttribute { }

Filter:

public class MyFilter : ActionFilterAttribute
{
    private readonly IMyService _myService;

    public MyFilter(IMyService myService)
    {
        _myService = myService;
    }

    public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        //do some with actionContext
        throw new Exception("You can`t go here");
    }
}

Controller method:

[My] // Not called
[HttpPost]
[Route("/do-some")]
public async Task DoSome(string myString)
{
     //do some
}

Register filter:

public partial class Startup 
{
    protected void ConfigureApi(IAppBuilder app, IContainer container) 
    {
        var configuration = new HttpConfiguration();
        //...
        var serviceInstance = container.GetInstance<IMyService>();
        configuration.Filters.Add(new MyFilter(serviceInstance));
    }
}

Is something wrong here?

TryBetter
  • 43
  • 5

1 Answers1

1

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:

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:

  1. 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}");
        }
    }
  1. 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);
        }
    }
  1. 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()
        {

        }
  1. The last step register my service
services.AddTransient<ISimpleService, SimpleService>();
  1. Results Results
DarkSideMoon
  • 835
  • 1
  • 11
  • 17