ASP.NET MVC IActionFilter IResultFilter IExceptionFilter/HandleError

一、IActionFilter

1、基本定义

  在action的执行前后进行AOP拦截。

IActionFilter接口定义如下:
public interface IActionFilter
{
  //执行方法之前   
void OnActionExecuted(ActionExecutedContext filterContext);   //----> ActionInvoke(xxxx) <-----执行Actin方法   
  //执行方法之后
  void OnActionExecuting(ActionExecutingContext filterContext);
}

2、实现方式

(1)、控制器重写IActionFilter实现方法

  控制器已经实现了接口IActionFilter,每次请求都会创建一个Controller实例,而且只执行一个Action方法,所以可以在控制器层次进行拦截,这样重载了的控制器的每个Action都会被拦截,Controller的定义如下:

  public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable,IExceptionFilter, IResultFilter, IAsyncController, IController, IAsyncManagerContainer

  所以,我们只需要重写已经实现的IActionFilter的两个方法,如下:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var contrllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;

            var actionName = filterContext.ActionDescriptor.ActionName;

            var parameter = filterContext.ActionDescriptor.GetParameters();

            filterContext.HttpContext.Response.Write(contrllerName + "_" + actionName);

            base.OnActionExecuting(filterContext);
        }

        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
        }

(2)、定义一个FilterAttribute

  定义Attribute放到不同的Action

 public class MyCustomAttribute : FilterAttribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {

        }

        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            //1.如果result不为空,那么就return了。不执行递归。。。
            filterContext.Result = new ViewResult()
            {
                ViewName = "Error"
            };
        }
    }

(3)、Global全局注入

  每一个action上面加特性,比较麻烦,我们可以选择进行全局的注入。

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());

            filters.Add(new MyCustomAttribute());
        }

二、IResultFilter

1、基本概念

  Action的返回值有几下几种,他们都是继承自ActionResult,其主要作用是对Action的执行结果进行转换,如利用内容协商,把结果数据序列化为指定格式的数据。

  ActionView、 ViewResult、JsonResult、ContentResult

  

  ActionResult定义如下:

  public abstract class ActionResult
  {
        public abstract void ExecuteResult(ControllerContext context);
  }

  在ActionResult的执行(调用ExecuteResult方法)前后进行AOP拦截。

  接口定义如下:

public interface IResultFilter
    {
        void OnResultExecuted(ResultExecutedContext filterContext);
        void OnResultExecuting(ResultExecutingContext filterContext);
    }

 2、实现方式

  同IActionFilter一样,有三种方式

  (1)、Controller上Override的

  public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable,IExceptionFilter, IResultFilter, IAsyncController,     IController, IAsyncManagerContainer

   public class HomeController : Controller
    {
        protected override void OnResultExecuting(ResultExecutingContext filterContext)
        {
           base.OnResultExecuting(filterContext);
        }

        protected override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);
        }
    }

  (2)、继承FilterAttribute,IResultFilter或ActionFilterAtrribute

public class MyActionFilterAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
          base.OnResultExecuting(filterContext);
     }

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

  (3)、GlobleFilters 全局的注册

  同IActionFilter

三、 IExceptionFilter HandleError

1、基本概念

  IExceptionFilter定义如下

public interface IExceptionFilter
    {
        void OnException(ExceptionContext filterContext);
    }

  public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable,IExceptionFilter, IResultFilter, IAsyncController,     IController, IAsyncManagerContainer

  Controller抽象类,接口IExceptionFilter的实现,空的

  protected virtual void OnException(ExceptionContext filterContext)
  {
  }

  HandleError是IExceptionFilter在MVC中的默认实现,也是默认注册在全局 

 public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    }

  HandleError当出现异常时候,转到一个错误页面,其源代码如下:

public virtual void OnException(ExceptionContext filterContext)
    {
      if (filterContext == null)
        throw new ArgumentNullException(nameof (filterContext));
      if (filterContext.IsChildAction || filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
        return;
      Exception exception = filterContext.Exception;
      if (new HttpException((string) null, exception).GetHttpCode() != 500 || !this.ExceptionType.IsInstanceOfType((object) exception))
        return;
      string controllerName = (string) filterContext.RouteData.Values["controller"];
      string actionName = (string) filterContext.RouteData.Values["action"];
      HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
      ExceptionContext exceptionContext = filterContext;
    //构造一个ViewResult,跳转到其对应View页面 ViewResult viewResult1
= new ViewResult(); viewResult1.ViewName = this.View; viewResult1.MasterName = this.Master; viewResult1.ViewData = (ViewDataDictionary) new ViewDataDictionary<HandleErrorInfo>(model); viewResult1.TempData = filterContext.Controller.TempData; ViewResult viewResult2 = viewResult1; exceptionContext.Result = (ActionResult) viewResult2;
    //ExceptionHandled标记已经处理 filterContext.ExceptionHandled
= true; filterContext.HttpContext.Response.Clear();
    //定义500错误 filterContext.HttpContext.Response.StatusCode
= 500; filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; }
    public string View
    {
      get
      {
     //view为空就是Error页面,Share文件夹下的Error.cshtml
if (string.IsNullOrEmpty(this._view)) return "Error"; return this._view; } set { this._view = value; } }

  

2、扩展例子

  不仅要错误页面,还要记录日志到数据库

 public class MyHandleErrorAttribute : FilterAttribute, IExceptionFilter// HandleErrorAttribute
    {
        public void OnException(ExceptionContext filterContext)
        {
            //记录日志。。。。my logic
            filterContext.ExceptionHandled = true;
        
//这个要设置为true,要不会继续抛出异常
base.OnException(filterContext); } }

  

   public class HomeController : Controller
    {
        [MyHandleError]
        public ActionResult Index()
        {
            throw new Exception("");
            return View();
        }
}

   配置Web.config

  <configuration>
  <system.web>
         <customErrors mode="On"/>
  </system.web>
  </configuration>

  可以直接跳到错误页面,要不直接显示红色的错误,黄色页。

原文地址:https://www.cnblogs.com/shawnhu/p/8417560.html