# 5个过滤器

1、AuthorizationFilter:鉴权授权
2、ResourceFilter:资源
3、ExceptionFilter:异常
4、ActionFilter:方法
5、ResultFilter:结果

# 过滤器执行顺序

Filter的执行顺序

# 过滤器多种扩展方式

  • 通过实现IActionFilter接口来完扩展。
public class SyloneActionFilterAttribute:Attribute,IActionFilter
  • 通过继承ActionFilterAttribute(系统提供的实现)。
public class SyloneActionFilterAttribute:ActionFilterAttribute
  • 异步版本的实现,通过实现IAsyncActionFilter接口来实现。
public class SyloneActionFilterAttribute:Attribute,IAsyncActionFilter

# 过滤器多种注入

  • 过滤器的特性可以定义在全局配置中,Filter必须是无参数构造函数,或者构造函数注入。
options.Filters.Add<GlobalExceptionFilter>();
  • 过滤器的特性可以定义在Action、Controller中
    • [CustomActionFilter]
      Filter必须是无参数构造函数。

    • [TypeFilter(typeof(MyFilterAttribute))]
      可以有参数构造函数,可以支持依赖注入。

    • [ServiceFilter(typeof(MyFilterAttribute))]
      可以有参数构造函数,可以支持依赖注入。但是如果要使用这个,必须在【Startup.cs】中注册服务。
      注册服务时若过滤器中使用的属性注入则必须使用第三方注入。

      builder.RegisterType(typeof(MyFilterAttribute)).PropertiesAutowired()
      

# ResourceFilter扩展定制做缓存

自定义一个特性类,继承Attribute,实现接口IResourceFilter,实现接口中的方法。
ResourceFilter

# ReusltFilter应用-开发双语言系统功能

双语言系统其实就需要两个视图,要根据语言的不同,来选择不同的视图;因为在渲染视图之前,会进入到OnResultExecuting方法,就可以在这个方法中确定究竟使用哪一个视图文件。
ReusltFilter应用

# ExceptionFilter异常处理

  • 实现方法,先判断,异常是都被处理过,如果没有被处理过,就处理。
  • 分情况处理:1.如果是ajax请求,就返回JsonReulst,如果不是Ajax,就返回错误页面。
public class CustomExceptionAttribute : Attribute, IExceptionFilter
{
    private readonly IModelMetadataProvider _modelMetadataProvider = null;
    /// <summary>
    /// 依赖注入:Model元数据的驱动
    /// </summary>
    public CustomExceptionAttribute(
   	 IModelMetadataProvider modelMetadataProvider
   	 ) {
   	 _modelMetadataProvider = modelMetadataProvider;
    }

    /// <summary>
    /// 当异常发生的时候出发到这里来
    /// </summary>
    /// <param name="context"></param>
    public void OnException(ExceptionContext context)
    {
   	 //判断异常有没有被处理过
   	 if (context.ExceptionHandled == false) {
   		 //没有处理过,在这里开始处理

   		 //如果是Ajax请求(看看Header是不是XMLHttpRequest)
   		 if (this.IsAjaxRequest(context.HttpContext.Request))
   		 {
   			 //中断式:如果对Result赋值,请求到这里结束了,不在继续Action
   			 context.Result = new JsonResult(new
   			 {
   				 Result = false,
   				 Msg = context.Exception.Message
   			 });
   		 }
   		 else {
   			 //跳转到异常页面
   			 var result = new ViewResult { ViewName = "~/Views/Errors.cshtml" };
   			 result.ViewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState);
   			 result.ViewData.Add("Exception", context.Exception);
   			 result.ViewData.Add("ErrDate", DateTime.Now);
   			 //中断式:如果对Result赋值,请求到这里结束了,不在继续Action
   			 context.Result = result;
   		 }
   		 context.ExceptionHandled = true;//指定异常已经被处理了
   	 }
    }

    /// <summary>
    /// 判断是不是Ajax请求
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    private bool IsAjaxRequest(HttpRequest request)
    {
   	 string header = request.Headers["X-Requested-With"];
   	 return "XMLHttpRequest".Equals(header);
    }
}
  • 注册到Action上,只对Action生效
    匿名Filter

  • 一般不会注册到Action上,一般会注册到全局(在【Startup.cs】中创建的【ConfigureServices】方法中进行全局注册)。
    匿名Filter

# ExceptionFilter-异常捕捉覆盖

  • 控制器实例化异常——能。
  • 异常发生在Try-cache中——不能,因为异常已经被捕捉到了。
  • 在视图中发生异常——不能。
  • 在Service层(业务逻辑层)中发生异常——能。
  • 在Action中发生异常——能。
  • 请求错误路径异常——不能(但是可以通过中间件解决)。

在【Startup.cs】中创建的【Configure】方法中进行使用,只要状态不是200,就可以处理

//只要不是200,都能进来
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");

app.UseExceptionHandler(errorApp => {
    errorApp.Run(async context =>
    {
   	 context.Response.StatusCode = 200;
   	 context.Response.ContentType = "text/html";
   	 await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
   	 await context.Response.WriteAsync("Error!!!<br><br>\r\n");
   	 var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();

   	 Console.WriteLine("------------------------------------------------");
   	 Console.WriteLine($"{ exceptionHandlerPathFeature?.Error.Message}");
   	 Console.WriteLine("------------------------------------------------");

   	 if (exceptionHandlerPathFeature?.Error is FileNotFoundException) {
   		 await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
   	 }

   	 await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
   	 await context.Response.WriteAsync($"<p>{ exceptionHandlerPathFeature?.Error.Message}</p><br>\r\n");
   	 await context.Response.WriteAsync("</body></html>\r\n");
   	 await context.Response.WriteAsync(new string(' ', 512));//IE padding

    });
});

# 避开Filter的检查

如果全局注册,Filter生效于所有的Action,如果有部分Action我希望你不生效,可以避开Filter的检查

  • [AllowAnonymous] 跳过登录验证
  • [IgnoreAntiforgeryToken] 跳过防范anti攻击
  • 自定义的匿名Filter
    • 自定义一个特性类,继承Attribute
      匿名Filter

    • 需要在需要匿名的Filter内部,检查是否需要匿名(检查是否标记的有匿名特)如果有就避开
      匿名Filter

    • 使用Action
      匿名Filter