前言

    过滤器,从我们开始开发 Asp.Net 应用程序开始,就一直伴随在我们左右;Asp.Net Core 提供多种类型的过滤器,以满足多种多样的业务应用场景;并且在 Asp.Net Core 本身,过滤器的应用也非常广泛;但是,在实际的业务场景中,大部分开发人员只使用到其中 1 到 2 种类型,当然,这其中大部分可能性是由于业务场景的适用性使然,本文尝试简单介绍 Asp.Net Core 中提供的各种过滤器,以及实际的应用场景,希望对您有所帮助。

1. 介绍

1.1 作用范围
        [CustomerActionFilter]
        public ActionResult<string> Get(int id)
        {
            return "value";
        }
1.2 过滤器的工作原理
1.3 过滤器类型,看下图

3. 授权过滤器

3.1 使用介绍

3.2 应用场景

    [Authorize]
    [Route("api/[controller]")]
    public class UserController : Controller
    {
        [AllowAnonymous]
        [HttpGet]
        public ActionResult<string> Get()
        {
            return "default";
        }

        [HttpPost]
        public ActionResult<string> Post()
        {
            return "default";
        }
    }

4. 资源过滤器

4.1 资源管理器实现自接口 IResourceFilter 或者 IAsyncResourceFilter,现在我们来实现一个资源过滤器,输出一行信息,看看执行顺序

    public class CustomerResourceFilter : Attribute, IResourceFilter
    {
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            Console.WriteLine("==== OnResourceExecuted");
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            Console.WriteLine("==== OnResourceExecuting");
        }
    }

4.2 对 HomeController 的操作应用该资源过滤器,看看对一个操作同时应用 CustomerActionFilter 和 CustomerResourceFilter ,他们的执行顺序是什么

    [Route("api/[controller]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        [HttpGet]
        [CustomerActionFilter]
        [CustomerResourceFilter]
        public async Task<ActionResult<IEnumerable<string>>> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }

4.3 启动程序,访问 http://localhost:5000/api/home,输出结果如下

5. 异常过滤器

5.1 创建一个异常过滤器

    public class CustomerExceptionFilter : Attribute, IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("发生了异常:{0}", context.Exception.Message);
            Console.ForegroundColor = ConsoleColor.Gray;
        }
    }

5.2 将 CustomerExceptionFilter 应用到 HomeController 上

    public class CustomerResourceFilter : Attribute, IResourceFilter
    {
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            Console.WriteLine("==== OnResourceExecuted");
        }

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            Console.WriteLine("==== OnResourceExecuting");
            throw new Exception("资源管理器发生了异常");
        }
    }

5.3 运行程序,访问 http://localhost:5000/api/home

    [Route("api/[controller]")]
    [ApiController]
    [CustomerResourceFilter]
    [CustomerExceptionFilter]
    public class HomeController : ControllerBase
    {
        // GET api/values
        [HttpGet]
        [CustomerActionFilter]
        public async Task<ActionResult<IEnumerable<string>>> Get()
        {
            throw new Exception("Get操作发生了异常");
            return new string[] { "value1", "value2" };
        }
    }

5.4 再次启动程序,访问 http://localhost:5000/api/home,控制台输出结果如下

5.5 客户端得到了一个友好的返回值

5.6 这是因为我们在异常过滤器内部将异常进行了出来,并通过设置 context.ExceptionHandled = true 来标记表示异常已经被处理,然后输出友好信息

    public class CustomerExceptionFilter : Attribute, IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("发生了异常:{0}", context.Exception.Message);
            Console.ForegroundColor = ConsoleColor.Gray;

            context.Result = new JsonResult(new { code = 500, message = context.Exception.Message });
            context.ExceptionHandled = true;
        }
    }

6. 操作过滤器 ActionFilterAttribute 和 结果过滤器 IResultFilter

6.1 之所以将这两个过滤器放在一起讲,是因为,这两个过滤器就像一对孪生兄弟一样,正所谓有始有终,首先来看操作过滤器

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public abstract class ActionFilterAttribute : Attribute, IActionFilter, IFilterMetadata, IAsyncActionFilter, IResultFilter, IAsyncResultFilter, IOrderedFilter
    {
        protected ActionFilterAttribute();

        //
        public int Order { get; set; }

        //
        public virtual void OnActionExecuted(ActionExecutedContext context);
        //
        public virtual void OnActionExecuting(ActionExecutingContext context);
        //
        [AsyncStateMachine(typeof(<OnActionExecutionAsync>d__6))]
        public virtual Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next);
        //
        public virtual void OnResultExecuted(ResultExecutedContext context);
        //
        public virtual void OnResultExecuting(ResultExecutingContext context);
        //
        [AsyncStateMachine(typeof(<OnResultExecutionAsync>d__9))]
        public virtual Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next);
    }

6.2 操作过滤器包含了 写入结果前(before)写入后(after)的方法,这使得我们可以不用去定义结果过滤器就可以实现对写入结果的管理

6.3 下面来看结果过滤的定义

    public class CustomerResultFilter : Attribute, IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext context)
        {
            Console.WriteLine("OnResultExecuted");
        }

        public void OnResultExecuting(ResultExecutingContext context)
        {
            Console.WriteLine("OnResultExecuting");
        }
    }

6.4 利用结果过滤器实现对输出结果的干预

    public class CustomerResultFilter : Attribute, IResultFilter
    {
        public void OnResultExecuted(ResultExecutedContext context)
        {
            // ToDo
        }

        public void OnResultExecuting(ResultExecutingContext context)
        {
            // 干预结果
            context.HttpContext.Response.Headers.Add("Author", "From Ron.liang");
        }
    }

6.5 输出结果

7.在过滤器中使用依赖注入

7.1 使用 GetService,以支持依赖注入

        public void OnResultExecuting(ResultExecutingContext context)
        {
            var env = (IHostingEnvironment)context.HttpContext.RequestServices.GetService(typeof(IHostingEnvironment));

            Console.ForegroundColor = ConsoleColor.Blue;
            Console.WriteLine("OnResultExecuting,{0}", env.EnvironmentName);
            Console.ForegroundColor = ConsoleColor.Gray;

            // 干预结果
            if (env.IsDevelopment())
                context.HttpContext.Response.Headers.Add("Author", "From Ron.liang");
        }

7.2 在过滤器中使用中间件

7.3 定义注册管理管道类

    public class RegisterManagerPipeline
    {
        public void Configure(IApplicationBuilder applicationBuilder)
        {
            CookieAuthenticationOptions options = new CookieAuthenticationOptions();

            applicationBuilder.UseCors(config =>
            {
                config.AllowAnyOrigin();
            });
        }
    }
    [Authorize]
    [Route("api/[controller]")]
    [MiddlewareFilter(typeof(RegisterManagerPipeline))]
    public class UserController : Controller
    {
        // GET: api/<controller>
        [AllowAnonymous]
        [HttpGet]
        public ActionResult<string> Get()
        {
            return "default";
        }
    }

8. 过滤器的执行顺序

8.1 Order 演示代码

        [HttpPost]
        [UserNameActionFilter(Order = 10)]
        [UserAgeActionFilter(Order = 5)]
        public void Post([FromBody] UserModel value)
        {
        }

8.2 输出结果

结束语

  • 本文简单介绍了 Asp.Net Core 下系统内置的各种各样的过滤器,分别是

  • 还通过一些简单说实例演示了过滤器的执行过程
  • 最后介绍了如何在过滤器中使用中间件,以及对过滤器的执行顺序进行了详细的演示

演示代码下载

https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.FilterDemo

01-06 13:00
查看更多