Search code examples
c#asp.net-coreactionfilterattributecustom-action-filter

How can I pass an instance of LoggerFactory to ActionFilterAttribute


Good day.

I'm trying to use logging by injecting a LoggerFactory in my custom ActionFilterAttribute class but when using the Attribute in one of the controller methods I get an error saying

[CS7036] There is no argument given that corresponds to the required formal parameter 'logger' of 'Tracker.Tracker(ILoggerFactory)' 

Here's the implementation of the class:

using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;

namespace ImmoSales.Tracking
{
    public class Tracker : ActionFilterAttribute
    {
        public string ActionType { get; set; }
        public string ActionName { get; set; }
        private readonly ILoggerFactory _logger;

        public Tracker(ILoggerFactory logger)
        {
            _logger = logger;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
        }

        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            base.OnResultExecuting(context);
        }

        public override void OnResultExecuted(ResultExecutedContext context)
        {
            base.OnResultExecuted(context);
        }
    }
}

I get the mentioned error when I attempt to use the Tracker in a controller as follows:

[Tracker(ActionType="testType", ActionName="testName")]
public IActionResult Index()
{
    return View();
}

What can be done to fix the error?


Solution

  • Since you are doing constructor injection in your action filter, you may enable it using ServiceFilter attribute where you can pass the type of your filter

    [ServiceFilter(typeof(Tracker))]
    public IActionResult Index()
    {
        // to do : return something
    }
    

    Make sure you have registered the filter in the ConfigureServices method

    services.AddScoped<Tracker>();
    

    If you want to pass other arguments to the filter, you can update the filter constructor to have those parameters.

    public class Tracker : ActionFilterAttribute
    {
        private string _actionType { get; set; }
        private string _actionName { get; set; }
        private readonly ILoggerFactory _logger;
    
        public Tracker(ILoggerFactory logger, string actionType, string actionName)
        {
            this._logger = logger;
            this._actionName = actionName;
            this._actionType = actionType;
        }
    
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
        }
    
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            base.OnActionExecuted(context);
        }
    
        public override void OnResultExecuting(ResultExecutingContext context)
        {
            base.OnResultExecuting(context);
        }
    
        public override void OnResultExecuted(ResultExecutedContext context)
        {
            base.OnResultExecuted(context);
        }
    }
    

    and use TypeFilter attribute to enable your filter, where you can explicitly pass the arguments

    [TypeFilter(typeof(Tracker), Arguments = new object[] { "Abc", "Xyz" })]
    public IActionResult Index()
    {
        // to do : return something
    }