Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write an action filter for all controllers

Here is a sample action filter. We know that when we write an action filter then we need to decorate the controller with an attribute like this, to use it for any controller.

I like to know whether there is any way to write an action filter which will work for all controllers in way that I do not need to decorate all the controllers with an action filter attribute. Any ideas?

[LogActionFilter]
public class HomeController : Controller
{}

public class LogActionFilter : ActionFilterAttribute

     {
          public override void OnActionExecuting(ActionExecutingContext filterContext)
          {
               Log("OnActionExecuting", filterContext.RouteData);       
          }

          public override void OnActionExecuted(ActionExecutedContext filterContext)
          {
               Log("OnActionExecuted", filterContext.RouteData);       
          }

          private void Log(string methodName, RouteData routeData)
          {
               var controllerName = routeData.Values["controller"];
               var actionName = routeData.Values["action"];
               var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
               Debug.WriteLine(message, "Action Filter Log");
          }

     }
like image 855
Thomas Avatar asked Sep 25 '14 07:09

Thomas


People also ask

Which filters are filters that are applied to all actions?

Action Filters − Action filters are used to implement logic that gets executed before and after a controller action executes.

How do I create a custom action filter in Web API?

Right-click on Controllers, select "Add" and click on "Controller". Select "Web API 2 Controller with read/write actions" and click the "Add" button. Name it "Home Controller". It will add a controller with 5 API methods.

Can we attach multiple filters to a single action?

If you need, you can apply multiple action filters to the same action. For example, you might want to apply both the OutputCache and HandleError action filters to the same action.


3 Answers

If you're already subclassing from a base controller, you don't need a filter attribute or to register anything. You can just override the desired methods, e.g.,

public class BaseController : Controller {
   protected override void OnActionExecuting(ActionExecutingContext filterContext) {
      ViewBag.SomeValue = "glorp frob blizz nunk";
      // Access the controller, parameters, querystring, etc. from the filterContext
      base.OnActionExecuting(filterContext);
   }
}

Then, every controller that subclasses from it will run that method:

public sealed class GlorpController : BaseController {
   public ActionResult Index() => View();
}

The view will quite happily see the ViewBag.SomeValue value.

like image 58
ErikE Avatar answered Nov 11 '22 15:11

ErikE


public class LogActionFilterAttribute : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
            Log("OnActionExecuted", filterContext.RouteData);    
        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            Log("OnActionExecuting", filterContext.RouteData);  
        }

        private void Log(string methodName, RouteData routeData)
        {
            var controllerName = routeData.Values["controller"];
            var actionName = routeData.Values["action"];
            var message = String.Format("{0} controller:{1} action:{2}", methodName, controllerName, actionName);
            Debug.WriteLine(message, "Action Filter Log");
        }
    }

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            GlobalFilters.Filters.Add(new LogActionFilterAttribute());
        }
    }
like image 45
Jason Li Avatar answered Nov 11 '22 15:11

Jason Li


For your scenario you can just make a Custom BaseController and put your [LogActionFilter] attribute on Custom Basecontroller and inherit all your Controllers from Custom Basecontroller as shown below :

[LogActionFilter]
public class MyBaseController : Controller
{

}

public class MyOtherController : MyBaseController //<----instead of using Controller as base use MyBaseController as base class
{
    public ActionResult Index()
    {
        // ...
    }
}

The advantage of this approach is that you have to put your custom [LogActionFilter] attribute only at one place i.e. only on Custom BaseController.

like image 25
Kartikeya Khosla Avatar answered Nov 11 '22 16:11

Kartikeya Khosla