Filter(过滤器)

总共有五种,Authorization Filter,Resource Filter,Exception Filter,Action Filter,Result Filter

Exception Filter

新增全局异常过滤器GlobalExceptionFilter.cs,

当出现异常时进入此方法,可在这针对不同的异常做相关处理并返回指定数据,避免直接把错误暴露给用户

public class GlobalExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
Exception ex = context.Exception;
string errMsg = "GlobalExceptionFilter-OnException:" + ex.Message;
if (context.Exception.GetType() == typeof(ExecuteException))
     {
    //针对不同的自定义异常,做不同处理
    MsgModel<string> msgModel = new MsgModel<string>()
    {
     Status = false,
     Msg = errMsg,
     Errcode = "AA001"
    };
     context.Result = new JsonResult(msgModel);
    context.ExceptionHandled = true;
    }
    else
    {
      context.Result = new JsonResult(errMsg);
      context.ExceptionHandled = true;
    }     LogHelper.Error(errMsg);
  }
}

然后在Startup.cs 注入过滤器

Action Filter 

新增全局过滤器GlobalActionFilter.cs

在方法执行前后,会跳转至以下两个方法,方便追踪接口执行情况

public class GlobalActionFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
    //LogHelper.Info("OnActionExecuted");
    //执行方法后执行这
   }   public void OnActionExecuting(ActionExecutingContext context)
  {
  //LogHelper.Info("OnActionExecuting");
  //执行方法前先执行这
  }
}

Authonization Filter

权限控制过滤器
通过 Authonization Filter 可以实现复杂的权限角色认证登陆授权等操作

/// <summary>
/// 实现自定义授权
/// </summary>
public class AuthorizeFilter : IAuthorizationFilter
{
/// <summary>
/// 请求验证,当前验证部分不要抛出异常,ExceptionFilter不会处理
/// </summary>
/// <param name="context"></param>
public void OnAuthorization(AuthorizationFilterContext context)
{

        //这里可以做复杂的权限控制操作
        //if (context.HttpContext.User.Identity.Name != "1") //简单的做一个示范
        //{
        // //未通过验证则跳转到无权限提示页
        // RedirectToActionResult content = new RedirectToActionResult("NoAuth", "Exception", null);
        // context.Result = content;
        //

        }
}

Resource Filter

资源过滤器
可以通过Resource Filter 进行资源缓存防盗链等操作。
使用Resource Filter 要求实现IResourceFilter 抽象接口

public class ResourceFilter : Attribute,IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
// 执行完后的操作
} public void OnResourceExecuting(ResourceExecutingContext context)
{
// 执行中的过滤器管道
}
}

Result Filter

结果过滤器,可以对结果进行格式化、大小写转换等一系列操作。

使用Result Filter 需要实现IResultFilter 抽象接口,接口要求实现
OnResultExecuting 方法 和OnResultExecuted 方法

    • OnResultExecuting :Called before the action result executes. 在操作结果执行之前调用
    • OnResultExecuted :Called after the action result executes. 在操作结果执行之后调用
public class ResultFilter : Attribute, IResultFilter
{
public void OnResultExecuted(ResultExecutedContext context)
{
// 在结果执行之后调用的操作...
} public void OnResultExecuting(ResultExecutingContext context)
{
// 在结果执行之前调用的一系列操作
}
}

完毕 可以在全局注入

 中间件

中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:

  • 选择是否将请求传递到管道中的下一个组件。
  • 可在管道中的下一个组件前后执行工作。

请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。

/// <summary>
/// 中间件
/// 记录请求和响应数据
/// </summary>
public class RequestMiddleware
{ private readonly RequestDelegate _next; /// <summary>
/// 日志接口
/// </summary>
private static Logger logger = LogManager.GetCurrentClassLogger(); private Stopwatch _stopwatch; public RequestMiddleware(RequestDelegate next)
{
_stopwatch = new Stopwatch();
_next = next;
} public async Task InvokeAsync(HttpContext context)
{
// 过滤,只有接口
if (context.Request.Path.Value.ToLower().Contains("api"))
{
context.Request.EnableBuffering();
Stream originalBody = context.Response.Body; _stopwatch.Restart(); // 获取 Api 请求内容
var requestContent = await GetRequesContent(context); // 获取 Api 返回内容
using (var ms = new MemoryStream())
{
context.Response.Body = ms; await _next(context);
ms.Position = 0; await ms.CopyToAsync(originalBody);
} context.Response.Body = originalBody; _stopwatch.Stop(); var eventInfo = new LogEventInfo();
eventInfo.Message = "Success";
eventInfo.Properties["Elapsed"] = _stopwatch.ElapsedMilliseconds;
eventInfo.Properties["RequestBody"] = requestContent; logger.Trace(eventInfo);
}
else
{
await _next(context);
}
} private async Task<string> GetRequesContent(HttpContext context)
{
var request = context.Request;
var sr = new StreamReader(request.Body); var content = $"{await sr.ReadToEndAsync()}"; if (!string.IsNullOrEmpty(content))
{
request.Body.Position = 0;
} return content;
}
}

然后在Startup

// 请求日志监控
app.UseMiddleware<RequestMiddleware>();

AOP(面向切面编程)

面向切面编程(AOP是Aspect Oriented Program的首字母缩写) ,我们知道,面向对象的特点是继承、多态和封装。而封装就要求将功能分散到不同的对象中去,这在软件设计中往往称为职责分配。实际上也就是说,让不同的类设计不同的方法。这样代码就分散到一个个的类中去了。这样做的好处是降低了代码的复杂程度,使类可重用。

但是人们也发现,在分散代码的同时,也增加了代码的重复性。什么意思呢?比如说,我们在两个类中,可能都需要在每个方法中做日志。按面向对象的设计方法,我们就必须在两个类的方法中都加入日志的内容。也许他们是完全相同的,但就是因为面向对象的设计让类与类之间无法联系,而不能将这些重复的代码统一起来。

也许有人会说,那好办啊,我们可以将这段代码写在一个独立的类独立的方法里,然后再在这两个类中调用。但是,这样一来,这两个类跟我们上面提到的独立的类就有耦合了,它的改变会影响这两个类。那么,有没有什么办法,能让我们在需要的时候,随意地加入代码呢?这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

一般而言,我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。这样看来,AOP其实只是OOP的补充而已。OOP从横向上区分出一个个的类来,而AOP则从纵向上向对象中加入特定的代码。有了AOP,OOP变得立体了。如果加上时间维度,AOP使OOP由原来的二维变为三维了,由平面变成立体了。从技术上来说,AOP基本上是通过代理机制实现的。      AOP在编程历史上可以说是里程碑式的,对OOP编程是一种十分有益的补充。

AOP是是OOP(面向对象)的补充和完善

拦截器是在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。

AOP说白了就是在运行时,动态的将代码切入到类的指定方法的指定位置上,这种思想就是面向切面的编程思想。

就是 在不修改源代码的基础上 添加新业务,比如 日志 性能检测

从思想上来说,Filter(过滤器)跟AOP(拦截器)极其接近
但是区别明显:
1、Filter只能拦截request的请求
2、Spring中的AOP,一般而言,是在Service层,拦截Bean(实例)的访问。
例如使用@Transcational 来拦截dao的应用,让它实现事务的管理。从思想上来说,Filter跟AOP极其接近

1、拦截器是基于java的反射机制,过滤器是基于java的函数回调

  2、拦截器不依赖于servlet容器,而过滤器依赖于servlet容器

  3、拦截器只能对action请求起作用,过滤器几乎对所有的请求起作用

  4、拦截器可以访问action上下文,值栈里的对象,而过滤器不能访问

  5、在action生命周期中,拦截器可以被多次调用,过滤器只能在servlet初始化时调用一次

  6、拦截器可以获取IOC容器中的各个bean,过滤器不行,在拦截器中注入一个service可以调用逻辑业务

Aop”其实就是动态代理

Interceptor(拦截器)

1,拦截器的概念
java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action
执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截
然后再之前或者之后加入某些操作。目前,我们需要掌握的主要是Spring的拦截器,Struts2的拦截器不用深究,知道即可。

2,拦截器的原理
大部分时候,拦截器方法都是通过代理的方式来调用的。Struts2的拦截器实现相对简单。当请求到达Struts2的ServletDispatcher时,Struts2
会查找配置文件,并根据配置实例化相对的拦截器对象,然后串成一个列表(List),最后一个一个的调用列表中的拦截器。Struts2的拦截器是可
插拔的,拦截器是AOP的一个实现。Struts2拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或者字段时,Struts2拦截器链
中的拦截器就会按照之前定义的顺序进行调用。

3,自定义拦截器的步骤
第一步:自定义一个实现了Interceptor接口的类,或者继承抽象类AbstractInterceptor。
第二步:在配置文件中注册定义的拦截器。
第三步:在需要使用Action中引用上述定义的拦截器,为了方便也可以将拦截器定义为默认的拦截器,这样在不加特殊说明的情况下,所有的
Action都被这个拦截器拦截。

4,过滤器与拦截器的区别
过滤器可以简单的理解为“取你所想取”,过滤器关注的是web请求;拦截器可以简单的理解为“拒你所想拒”,拦截器关注的是方法调用,比如拦截
敏感词汇。
4.1,拦截器是基于java反射机制来实现的,而过滤器是基于函数回调来实现的。(有人说,拦截器是基于动态代理来实现的)
4.2,拦截器不依赖servlet容器,过滤器依赖于servlet容器。
4.3,拦截器只对Action起作用,过滤器可以对所有请求起作用。
4.4,拦截器可以访问Action上下文和值栈中的对象,过滤器不能。
4.5,在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时调用一次。

LogInterceptor

安装Castle.Core,Autofac.Extras.DynamicProxy

新建LogInterceptor.cs ,继承IInterceptor

   public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
Dapper.Logger.LogHelper.logger.Info(invocation.Method.Name);
}
catch (Exception ex)
{
Dapper.Logger.LogHelper.logger.Error(invocation.Method.Name + " " + ex.ToString());
}
}
}

在Startup.cs 新增以下代码

针对某个类或者某个方法做拦截时

首先新建一个拦截器 MyInterceptor

    public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
NLogHelper.logger.Info(invocation.Method.Name);
}
catch (Exception ex)
{
NLogHelper.logger.Error(invocation.Method.Name + " " + ex.ToString());
}
}
}

然后Startup.cs 中ConfigureContainer代码如下

把LogInterceptor 代码注释,但是要保留接口拦截EnableInterfaceInterceptors() ,注入MyInterceptor

public void ConfigureContainer(ContainerBuilder builder)
{
//builder.RegisterType<LogInterceptor>(); builder.RegisterType<MyInterceptor>(); builder.RegisterType<DbFactory>().As<IDbFactory>(); //业务逻辑层所在程序集命名空间
Assembly service = Assembly.Load("Summer.Service"); //注:webapi要引用接口和类,不然这里读不到
//接口层所在程序集命名空间
Assembly repository = Assembly.Load("Summer.IService");
//自动注入
builder.RegisterAssemblyTypes(service, repository)
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope()
.EnableInterfaceInterceptors() //开启接口拦截
//.InterceptedBy(typeof(LogInterceptor)) //设置全局拦截器,统一由LogInterceptor拦截所有接口的调用
;
}

然后在需要拦截的接口中添加以下代码

拦截器设置完毕,当调用ITestService 的全部方法都会跳转拦截器

 这里是一个示例 利用反射查看权限

public class AuthInterceptor : IInterceptor
{ public void Intercept(IInvocation invocation)
{ Type tt = invocation.InvocationTarget.GetType();
DoMain.Model.SYS.SYS_User userinfo = null; var p = tt.GetProperties().FirstOrDefault(q => q.Name == "UserInfo"); userinfo = (DoMain.Model.SYS.SYS_User)p.GetValue(invocation.InvocationTarget);
var authkey = invocation.TargetType.ToString() + "." + invocation.Method.Name; if (AuthChecker.isAuth(userinfo, authkey))
{
invocation.Proceed();
}
else
{
throw new Core.AuthException("没有操作权限");
} //方法执行后的操作 }

Filter和 LogInterceptor 可以同时共存,执行顺序是:

ActionFilter 的OnActionExecuting =》LogInterceptor 的Intercept =》ActionFilter 的OnActionExecuted

如果接口有异常,不会跳转LogInterceptor ,而是进入ExceptionFilter,顺序是:

ActionFilter 的OnActionExecuting =》ActionFilter 的OnActionExecuted =》ExceptionFilter 的OnException

AOP的应用

引入三个包,通过Nuget安装,Autofac开头,如下

注: 其中Autofac.Extras.DynamicProxy就是AOP相关组件,其中包含了Castle.Core,所以不用单独安装Castle.Core.

总结:

  AOP在做一些业务前置或后置处理上时很有用的,使用比较灵活,无需修改原有代码逻辑,比起修改原有代码维护相对好多啦!!!

.net core 3.1 过滤器(Filter) 与中间件与AOP面向切面 与拦截器及其应用的更多相关文章

  1. .NET Core 实现动态代理做AOP(面向切面编程)

    1.介绍 1.1 动态代理作用 用动态代理可以做AOP(面向切面编程),进行无入侵式实现自己的扩展业务,调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,比如:日志记录.性能统计.安全控制.事务 ...

  2. Asp.Net MVC3 简单入门详解过滤器Filter(转)

    前言 在开发大项目的时候总会有相关的AOP面向切面编程的组件,而MVC(特指:Asp.Net MVC,以下皆同)项目中不想让MVC开发人员去关心和写类似身份验证,日志,异常,行为截取等这部分重复的代码 ...

  3. Asp.Net MVC3 简单入门详解过滤器Filter

    http://www.cnblogs.com/boruipower/archive/2012/11/18/2775924.html 前言 在开发大项目的时候总会有相关的AOP面向切面编程的组件,而MV ...

  4. 【转】Asp.Net MVC3 简单入门详解过滤器Filter

    原文地址:http://www.cnblogs.com/boruipower/archive/2012/11/18/2775924.html 前言 在开发大项目的时候总会有相关的AOP面向切面编程的组 ...

  5. 过滤器(Filter)和拦截器(Interceptor)

    过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...

  6. 过滤器(Filter)与拦截器(Interceptor )区别

    目录 过滤器(Filter) 拦截器(Interceptor) 拦截器(Interceptor)和过滤器(Filter)的区别 拦截器(Interceptor)和过滤器(Filter)的执行顺序 拦截 ...

  7. Asp.Net MVC3 简单入门详解过滤器Filter(转载)

    前言 在开发大项目的时候总会有相关的AOP面向切面编程的组件,而MVC(特指:Asp.Net MVC,以下皆同)项目中不想让MVC开发人员去关心和写类似身份验证,日志,异常,行为截取等这部分重复的代码 ...

  8. java中过滤器(Filter)与拦截器(Interceptor )区别

    过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是设置字符集.控制权限.控制转向.做一些业务逻辑判断等.其工作 ...

  9. Spring Boot之拦截器与过滤器(完整版)

    作者:liuxiaopeng 链接:http://www.cnblogs.com/paddix 作者:蓝精灵lx原文:https://blog.csdn.net/liuxiao723846/artic ...

随机推荐

  1. CSS3 学习笔记(中)

    七.文档流 文档流(normal flow)--网页的基础(最底下的一层),我们所创建的元素默认都是在文档流中进行排列. 对于元素有两个状态:在文档流 或 脱离文档流. 元素在文档流的特点: 块元素: ...

  2. python之迭代器,生成器小结

    1.凡是可作用于for循环的对象都是Iterable类型: 2.凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列: 3.集合数据类型如list.dict.str等 ...

  3. Docker 指南

    一.docker 介绍 1.1 引言 环境不一致 "我本地运行没问题啊?!" 多用户相互影响 "哪个哥们又写死循环了,怎么这么卡?!" 运维成本高 " ...

  4. GitHub上最火的、最值得前端学习的几个数据结构与算法项目!没有之一!

    Hello,大家好,我是你们的 前端章鱼猫. 简介 前端章鱼猫从 2016 年加入 GitHub,到现在的 2020 年,快整整 5 个年头了. 相信很多人都没有逛 GitHub 的习惯,因此总会有开 ...

  5. Python_爬虫养殖专业户_01

    永远记住,动手比动嘴有价值! 构建一个爬虫的四大步骤: 1. 获取URL url= 2. User-Agent伪装 headers = { 'User-Agent': 'Mozilla/5.0 (Ma ...

  6. 转:csdn怎么快速别人的文章

    在csdn看到好的文章想转载,无奈找不到转载的功能,只能想办法了. 首先确定原文允许转载 在文章开头处一般有版权声明,如图 转载时要注明出处和作者 如何转载 用谷歌浏览器加载文章地址,打开文章 F12 ...

  7. Azure Cosmos DB (五) .Net Core 控制台应用

    一,引言 之前在讲Azure CosmosDB Core(SQL)核心的时候,使用了EF Core 的方式,引用了 "Microsoft.EntityFrameworkCore.Cosmos ...

  8. 记一次UE4源码编译和游戏项目打包过程

    1.首先我们需要注册一个Epic账户,网址如下 http://api.unrealengine.com/CHN/GettingStarted/Installation/index.html#bookm ...

  9. 网鼎杯2020 AreUSerialz

    0x00 前言 ...有一说一,赵总的BUUCTF上的这道题目并没有复现到精髓.其实感觉出题人的题目本身没有那么简单的,只不过非预期实在是太简单惹. 涉及知识点: 1.php中protected变量反 ...

  10. Oracle函数:trunc、round、ceil和floor

    1.trunc函数 1).trunc(date) 格式:trunc(date,fmt) trunc用于截取时间,即便你指定不同的格式类型,返回的类型始终都是时间类型. 示例: with dates a ...