Asp.net core 中实现AOP面向切面编程
面向切面编程的含义:比面向对象编程更细化,比如在类前边加点东西,在类后边加点东西,先来比较一下主要的集中编程思想。
- POP编程:线性思维的方式来编程;
- OOP编程:面向对象编程,从对象的角度出发,先考虑有哪些对象,然后考虑对象应该具有的属性和方法,OOP可以应对复杂的业务需求,不管做多复杂的系统,都可以将功能拆分成一个个的类实现;
- AOP编程:可以在不破坏类封装的情况下,可以任意的扩展类的功能,可以方便代码复用,可以让程序员更专注于核心业务;
AOP实现的方式:
- 静态方法:代理模式 & 装饰器模式
- 动态实现:dynamic proxy
- 最常用的:Filter(MVC)& IOC容器扩展实现AOP
4.DDD领域驱动设计:有边界的意识。面向过程没有边界思想,在面向对象的开发环境中,对象就是边界(都装到盒子里,盒子就是边界,方便管理,以盒子为单位进行管理,管理的基础单位就会少一点),在编程的过中,考虑的不是对象,而是domain。
AOP的优点
1.在面向对象的思想中,只能对类为整体进行替换,对类本身没有办法扩展(在不更改类内部代码的前提下)
2.业务逻辑之外的东西,都可以依靠AOP来实现(比如认证和记录日志)
使用静态代理模式实现AOP
使用开发者模式中的代理者模式
1.声明一个接口:
public interface IDBHelp
{
int Save(UserInfo userInfo);//接口是要传参数的;
}
2.声明实现接口的类:
public class DBHelp:IDBHelp
{
public int Save(UserInfo userInfo)
{
Console.WriteLine("数据写入sqlserver数据库");
return default(int);
}
}
3.当想要对IDBhelp类进行扩展的时候(比如前后加上日志输出到控制台)
声明一个代理类(Proxy)
public class DBHelperProxy : DBHelp //代理模式
{
private IDBHelp _IdbHelper = new MySqlServer();//声明想要代理的类的实例
private ILogHelp logHelp = new LogConsole();//日志文件的实例
private void Before()
{
logHelp.Log("Prepar Save");
}
//IDBHelp类本身自带的方法
public int Save(UserInfo userInfo)
{
this.Before(); //在前边加个日志;
var Result= _IdbHelper.Save(userInfo);
this.After(); //在后边加个日志
return Result;
}
public void After()
{
logHelp.Log("After Save");
}
}
4.对Proxy类进行调用: 令接口 = Proxy
IDBHelp dBHelp1 = new DBHelperProxy();
dBHelp1.Save(userInfo1);
装饰器模式和代理模式实现原理基本相同,都是静态方法,此处不再赘述;
动态实现的方法:
有Remoting方法和Emit方法:
- Remoting中要调用固定的代码
- Emit使用的比较少
基于AOP Filter来实现
Core WebApi:的几种过滤器:
1.授权过滤器:AuthorizeAttribute.
2.异常过滤器:IExceptionFilter , IAsyncExceptionFilter
3.方法过滤器: ActionfilterAttribute, IActionFilter , IAsyncActionFilter.
后边两种是相对asp.net framwork来讲,asp.net core所特有的
4.资源过滤器:IResourceFilter
5.结果过滤器:ResultFilterAttribute, IResultFilter, IAsyncResultFilter
IResourceFilter的使用方法
将resourcefilter做成attribute后,加到http请求上,注意执行的顺序
1.新建CustomResourceFilterAttribute类
public class CustomResourceFilterAttribute : Attribute, IResourceFilter //注意必须继承的父类和接口;
{
public void OnResourceExecuting(ResourceExecutingContext context)
{
Console.WriteLine("this is CustomResourceFilterAttribute.OnResourceExecuting ");//HTTP请求函数执行前先执行他
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
Console.WriteLine("this is CustomResourceFilterAttribute.OnResourceExecuted ");///HTTP请求函数执行后再执行他
}
}
2.将特性加到要调用的Http请求上:
public class FilterController : ControllerBase
{
public FilterController()
{
Console.WriteLine("当前的这个 FilterController 被构造");
}
[Route("GET")]
[HttpGet]
[CustomResourceFilter]
public string Get()
{
Console.WriteLine("get方法了");
return "this is zhao-001";
}
}
观察控制台上的执行顺序。比构造函数执行还要早
正式因为IResoultFilter的这个特性,所以用来做缓存:
3.在IResoultFliter类类里面,具体代码实现如下:
public class CustomResourceFilterAttribute : Attribute, IResourceFilter //注意继承的父类和接口;
{
private static Dictionary<string, object> dictionaryCache = new Dictionary<string, object>();//声明一个字典类型
public void OnResourceExecuting(ResourceExecutingContext context)
{
string key = context.HttpContext.Request.Path.ToString();
//读取缓存发生在这里:
if (dictionaryCache.ContainsKey(key))
{
context.Result = dictionaryCache[key] as ObjectResult;//Result短路器
}
Console.WriteLine("this is CustomResourceFilterAttribute.OnResourceExecuting ");
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
//缓存的存储发生在这
string key = context.HttpContext.Request.Path.ToString();
Console.WriteLine($"key的值是{key}");//请求的路由地址;
ObjectResult objectResult = context.Result as ObjectResult;
dictionaryCache[key] = objectResult;
Console.WriteLine("this is CustomResourceFilterAttribute.OnResourceExecuted ");
}
}
注意: context.result=…这段代码俗称Result断路器,意思是遇到这段代码,就直接返回结果,程序不往下走了;
4.运行程序,刷新界面,发现时间不变,说明已经使用了缓存。
IActionFilterAttribute的使用方法:
运行结果,观察他的执行顺序:
参考文献
侵权联系删除