punkouter
punkouter

Reputation: 5366

How can I use Base Controller in ASP.NET to record user actions?

I am required to record user action and I don't want to have code in every method is every controller so would it make sense to somehow do this in the basecontroller ? OR is there a better way?

public class BaseController : Controller
{
    protected ILogger logger;

    public BaseController(ILogger<BaseController> logger)
    {
        this.logger = logger;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        //How do I get the current controller? 
        //How do I get the current method being called? 
        //How can I pass in additional parameters?
        //How can I get the user? 

        logger.LogWarning("Loaded BaseController");
        base.OnActionExecuting(context);
    }

}

Upvotes: 1

Views: 2862

Answers (2)

Alex Kartynnik
Alex Kartynnik

Reputation: 119

For getting controller & action names you can use ActionDescriptor of ActionExecutingContext

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var descriptor = filterContext.ActionDescriptor;
    var actionName = descriptor.ActionName;
    var controllerName = descriptor.ControllerDescriptor.ControllerName;
    ......
    base.OnActionExecuting(filterContext);
}

Regarding User information: controller initialisation will occur before authorisation takes place. So all of yours controllers will be created before any OnAuthorization takes place.

Approach to deal with these situations is to use Action Filters. The Authorize Attribute is fired early than controller initialisation occur.

Have a look this articles:

Upvotes: 1

Felipe Oriani
Felipe Oriani

Reputation: 38638

There are many ways to do that.

First: You could create your own base controller and implement OnActionExecution as you did. See the sample bellow to get information from ActionExecutingContext.

If you go this way, every controller that inhirits from this base controller will get the implementation of the logger because you are overriding OnActionExecuting (that applies to all actions of your controller).

public override void OnActionExecuting(ActionExecutingContext context)
{
    //How do I get the current controller? 
    string controllerName = context.ActionDescriptor.ControllerDescriptor.ControllerName

    //How do I get the current method being called? 
    string actionName = context.ActionDescriptor.ActionName;

    //How can I pass in additional parameters?
    foreach (var parameter in context.ActionParameters)
    {
        var parameterKey = parameter.Key;
        var parameterValue = parameter.Value;
    }

    //How can I get the user? 
    var user = this.User; // IPrinciple instance, explore this object

    logger.LogWarning("Loaded BaseController");
    base.OnActionExecuting(context);
}

Second: On the other hand, you can use ActionFilters which is a class that inhirits from ActionFilter class and do the same implementation on this classe overriding the OnActionExecuting. Then you can decorate your controllers with this attribute to make the logger. Given it is an attribute, you have to define the name fo the class with a sufix Attribute and use without it. For sample:

public class LoggerAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
       // same code above
    }
}

[Logger]
public class CustomerController : Controller
{
   // actions code...
}

Third: Use the same action filter class and instead of applying on all classes you want, you define it as a global action filter and it will be applied to all controllers. You have to define it on GlobalFilter and if you are using the default template of asp.net mvc, you can define it on the FilterConfig.cs, for sample:

filters.Add(new LoggerAttribute());

Upvotes: 5

Related Questions