How to write an action filter for all controllers

2019-02-09 21:52发布

问题:

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");
          }

     }

回答1:

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());
        }
    }


回答2:

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.



回答3:

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.