在.NET Core中三种实现“可插拔”AOP编程方式(附源码)
一看标题肯定会联想到使用动态编织的方式实现AOP编程,不过这不是作者本文讨论的重点。
本文讨论另外三种在netcore中可实现的方式,Filter(过滤器,严格意义上它算是AOP方式),DynamicProxy(动态代理方式,JAVA上早已不是新鲜事),Middleware(netcore中间件所实现的AOP方式)
什么是AOP编程
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
换白话文就是:保证开闭原则的前提下,不修改某一个模块(或函数)的任何一行代码,从而实现对该模块的横向扩展。
可插拔:即使抛弃AOP,核心内容仍然可以运行,降低耦合,提高可重用。
创建一个“能说你好,某某某”的ASP .NET CORE WebApi项目
创建项目步骤此处略过,呵呵。
我们假定一个最简单的“Say Hello”作为项目需求,通过URL传递姓名,再返回“hello {name}”。因此创建一个简单模型PeopleModel,创建一个接口ISay,并用Say实现ISay中的“hello {name}”功能。
public interface ISay
{
PeopleModel SayHello(PeopleModel peopleModel);
}
public class Say : ISay
{
public PeopleModel SayHello(PeopleModel peopleModel)
{
peopleModel.Name = $"hello {peopleModel.Name}";
return peopleModel;
}
}
public class PeopleModel
{
public string Name { get; set; } = "";
public int Age { get; set; }
public int Sex { get; set; }
}
再创建一个MVC控制器
[Route("api/[controller]")]
[ApiController]
public class DemoController : ControllerBase
{
[HttpGet]
public PeopleModel Get([FromQuery] PeopleModel peopleModel)
{
return Say.SayHello(peopleModel);
}
}
很简单的,不做解释,以免浪费篇幅。
DynamicProxy方式
动态代理的方式在JAVA上很早就出现了,比如在Spring框架里面。而NET中利用Autofac和Castle这两个框架同样也可以实现动态代理。
需要用到的框架如下:
Autofac:提供容器控制
Autofac.Extensions.DependencyInjection:对autofac依赖注入进行扩展
Autofac.Extras.DynamicProxy:对autofac动态代理进行扩展
Castle.Core:使用动态代理的实现
相信autofac很多朋友都不陌生了,而配合Castle框架就能实现动态代理模式,我们新建一个拦截器类,名为InjectInterceptor,而且必须要实现IInterceptor(该接口在Castle.DynamicProxy中),完整代码如下:
using System;
using Castle.DynamicProxy; namespace InterceptDemo.Intercepts.Inject
{
public class InjectInterceptor : IInterceptor
{
public virtual void Intercept(IInvocation invocation)
{
PreProceed(invocation);
invocation.Proceed();
PostProceed(invocation);
} private void PreProceed(IInvocation invocation)
{
Console.WriteLine($"{DateTime.Now} inject interceptor invoke preproceed");
} private void PostProceed(IInvocation invocation)
{
Console.WriteLine($"{DateTime.Now} inject interceptor invoke postproceed");
}
}
}
当继承IInterceptor接口时,必须要实现Intercept虚方法,该方法将传递IInvocation接口参数,调用Proceed函数将会实现方法体以外的函数,就是切面以外的函数。使用时只需要通过特性即可实现AOP方式,我们稍微修改一下Say这个类,增加一句话:[Intercept(typeof(InjectInterceptor))]
当然,还需要在autofac中实现注册才行,代码如下:
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<Say>().As<ISay>().EnableInterfaceInterceptors();
builder.RegisterType<InjectInterceptor>();
Filter方式
过滤器的方式就更加简单了,在ASP.NET框架中,使用过滤器的地方非常非常的多,笔者不作一一介绍,直接贴代码:
public class ActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
Console.WriteLine($"{DateTime.Now} on action exceuting");
} public override void OnActionExecuted(ActionExecutedContext context)
{
Console.WriteLine($"{DateTime.Now} on action exceuted");
}
}
Middleware方式
中间件不仅可以实现自定义管道,还也可以作为netcore invoke的AOP编程。我们先建立一个对ApplicationBuilder的扩展类
public static class InterceptHandler
{
public static IApplicationBuilder UseInterceptMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<InterceptMiddlware>();
}
}
再建立一个中间件
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; namespace InterceptDemo.Intercepts.Middleware
{
public class InterceptMiddlware
{
private readonly RequestDelegate _next; public InterceptMiddlware(RequestDelegate next)
{
_next = next;
} public async Task Invoke(HttpContext context)
{
PreProceed(context);
await _next(context);
PostProceed(context);
} private void PreProceed(HttpContext context)
{
Console.WriteLine($"{DateTime.Now} middleware invoke preproceed");
} private void PostProceed(HttpContext context)
{
Console.WriteLine($"{DateTime.Now} middleware invoke postproceed");
}
}
}
运行结果如下
总结一下
在NETCORE中可以使用AOP的方式有很多很多,包括国内优秀的开源框架asp.netcore同样可以实现AOP编程模式。
笔者所提供的三种AOP方式可适用如下
Filter:身份验证,参数验证,处理耗时等等WEB处理级的服务。
DynamicProxy:功能模块之间的解耦和重用服务。
Middleware:Request和Response之间建立的通信等底层服务,必要时还可以实现自定义管道。
感谢阅读!
源码地址:https://github.com/steveleeCN87/C-.three.aop.programming
在.NET Core中三种实现“可插拔”AOP编程方式(附源码)的更多相关文章
- 微信小程序中如何实现分页下拉加载?(附源码)
转眼间坚持写教你微信小程序系列已经有十节系列课程了,每天的工作压力繁重,小女子也不知道自己还能坚持这样的系列教程多久.只希望每篇教程真的对大家有帮助.这节课我们要介绍的就是如何实现分页的下拉加载,我们 ...
- .NET Core 中三种模式依赖注入的生命周期。
注入模式 同一个请求作用域 不同的请求作用域 AddSingleton 同一个实例 同一个实例 AddScoped 同一个实例 新实例 AddTransient 新实例 新实例
- EF Core 快速上手——EF Core的三种主要关系类型
系列文章 EF Core 快速上手--EF Core 入门 本节导航 三种数据库关系类型建模 Migration方式创建和习修改数据库 定义和创建应用DbContext 将复杂查询拆分为子查询 本 ...
- iOS开发UI篇—iOS开发中三种简单的动画设置
iOS开发UI篇—iOS开发中三种简单的动画设置 [在ios开发中,动画是廉价的] 一.首尾式动画 代码示例: // beginAnimations表示此后的代码要“参与到”动画中 [UIView b ...
- C#中三种定时器对象的比较
·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.Windows.Forms里2.定义在System.Threading.Timer类里3.定义在System.Timers ...
- 转-Web Service中三种发送接受协议SOAP、http get、http post
原文链接:web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 一.web服务中三种发送接受协议SOAP/HTTP GET/HTTP POST 在web服务中,有三种可供选择的发 ...
- C#中三种定时器对象的比较 【转】
https://www.cnblogs.com/zxtceq/p/5667281.html C#中三种定时器对象的比较 ·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.W ...
- Spring中三种配置Bean的方式
Spring中三种配置Bean的方式分别是: 基于XML的配置方式 基于注解的配置方式 基于Java类的配置方式 一.基于XML的配置 这个很简单,所以如何使用就略掉. 二.基于注解的配置 Sprin ...
- 深入浅出spring IOC中三种依赖注入方式
深入浅出spring IOC中三种依赖注入方式 spring的核心思想是IOC和AOP,IOC-控制反转,是一个重要的面向对象编程的法则来消减计算机程序的耦合问题,控制反转一般分为两种类型,依赖注入和 ...
随机推荐
- python——位运算之进制转化
>>> a=0b001100 >>> a 12 >>> b=0o001100 >>> b 576 >>> c= ...
- SpringBoot +Pom.xml工程资源文件配置
继承spring-boot-starter-parent 要成为一个spring boot项目,首先就必须在pom.xml中继承spring-boot-starter-parent,同时指定其版本 & ...
- 2017-11-03 Fr OCT 球体积的导数为球表面积
上学期学立体几何时注意到这一点.去问林老师,没听明白(写完笔记后发现林老师讲得是对的,惭愧).今天下午考历史的时候突然想起来. 除了球体积的导数为球表面积外,还注意到圆体积的导数为圆周长.今天中午看w ...
- Spring再接触 注入类型
共有三种注入类型 一种是set注入 一种是构造注入 一种是接口注入 最常用的还是set 现在看一下construct 构造注入 在userservice中加入 package com.bjsxt.se ...
- aptana怎么显示空格 tab和回车等
- 坑之mysql 字符串与数字操作
select "123"+1 = 124; select "1a23"+1 = 2; select "aa23"+1 = 1; select ...
- JPA和SpringData知识梳理
一. JPA,全称Java Persistence API,用于对象持久化的API,定义一套接口,来规范众多的ORM框架,所以它是在ORM框架之上的应用. 下面主要讲JPA在Hibernate基础上的 ...
- effector - 必应词典
effector - 必应词典 美[ɪ'fektə(r)]英[ɪ'fektə(r)] n.效应物 网络效应器:效果器:受动器 变形复数:effectors:
- mysql 判断字符串是否有某个字符
代码: SELECT LOCATE("_","a_123") -->2 (返回字符的位置,从1开始) SELECT ('123' REGEXP '[^0 ...
- 【转】Cron表达式详解
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式: (1) Seconds Minutes Hours DayofMonth Mo ...