前言

  其实好多项目中,做一些数据拦截、数据缓存都有Aop的概念,只是实现方式不一样;之前大家可能都会利用过滤器来实现Aop的功能,如果是Asp.NetCore的话,也可能会使用中间件; 而这种实现方式都是在请求过程中进行拦截,如果我们想在服务层中做切面的话,那种方式显然不好使了,需要用到“真正的Aop”。

直接开始

  其实我们常说的“真正的Aop”其实就是动态代理,理论知识我这里就不记录了,自己也写不好,大家自行找度娘,我们这直接上代码:

  正常搭建一个控制台项目,目录结构如下:

  这里就是模拟一个简单的用户维护,代码内容如下:

    定义Model

1
2
3
4
5
public class User
    {
        public string Name { getset; }
        public int Age { getset; }
    }

    定义接口

1
2
3
4
public interface IUserService
    {
        bool AddUser(User user);
    }

    实现接口

1
2
3
4
5
6
7
8
public class UserService : IUserService
    {
        public bool AddUser(User user)
        {
            Console.WriteLine("用户添加成功");
            return true;
        }
    }

  main方法

1
2
3
4
5
6
7
8
9
10
11
class Program
    {
        static void Main(string[] args)
        {
            User user = new User {Name="Zoe", Age=18 };
            IUserService userService = new UserService();
            userService.AddUser(user);
 
            //Console.ReadLine();
        }
    }

  项目很简单,正常运行就行;

  

  新需求,如果我们想在用户增加前和增加后都做点其他事,怎么做呢?

  解决方案:

    1. 直接修改服务层代码,执行存储前后分别处理相关业务就行了;

    2. 使用Aop,不修改原有方法。

  方案1我们就不说了,肯定大家都知道,功能肯定能实现,但需要原有代码,加入好多接口都要处理类似的事情怎么办? 如果加好了,下个版本针对某些功能不需要了怎么办?显然不是很灵活,而且这样重复改,出Bug的几率很大哦!!!

  直接动态代理:

    1. 增加一个类,进行业务操作;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
 
namespace Aop
{
    public class MyDecorator : DispatchProxy
    {
        //具体类型
        public object TargetClass { getset; }
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            Console.WriteLine("增加用户前执行业务");
 
            //调用原有方法
            targetMethod.Invoke(TargetClass, args);
 
            Console.WriteLine("增加用户后执行业务");
             
            return true;
        }
    }
}

  优化 Main()函数的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Program
   {
       static void Main(string[] args)
       {
           User user = new User {Name="Zoe", Age=18 };
           IUserService userService = new UserService();
           userService.AddUser(user);
 
           //动态代理
           //1. 创建代理对象
           IUserService userService1 = DispatchProxy.Create<IUserService, MyDecorator>();
           //2. 因为调用的是实例方法,需要传提具体类型
           ((MyDecorator)userService1).TargetClass = new UserService();
           userService1.AddUser(user);
 
           Console.ReadLine();
       }
   }

  看动态代理部分,这样就统一实现了用户维护服务层的Aop编程,看运行结果:

  

  这样是不是比较灵活了,自己不需要在一个个业务层中进行处理,而且取舍也很简单,不要就不适用此类就行了。

  引用第三方库

  原生的这种方式使用感觉有点麻烦,还有什么强制转换啊,传类型啊等这些,Castle.Core就帮我们把事都做好了,接下来我们看看怎么用。

  1. 首先引入Castle.Core;

  2. 新增拦截器类,做业务扩展;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Text;
 
namespace Aop
{
    class MyIntercept : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            //执行原有方法之前
            Console.WriteLine("增加用户前执行业务");
 
            //执行原有方法
            invocation.Proceed();
 
            //执行原有方法之后
            Console.WriteLine("增加用户后执行业务");
        }
    }
}

  3. Main函数增加Castle.Core的用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using AopModel;
using AopService;
using Castle.DynamicProxy;
using System;
using System.Reflection;
using System.Reflection.Metadata;
 
namespace Aop
{
    class Program
    {
        static void Main(string[] args)
        {
            User user = new User {Name="Zoe", Age=18 };
            IUserService userService = new UserService();
            userService.AddUser(user);
 
            Console.WriteLine("=============动态代理==============");
 
            //动态代理
            //1. 创建代理对象
            IUserService userService1 = DispatchProxy.Create<IUserService, MyDecorator>();
            //2. 因为调用的是实例方法,需要传提具体类型
            ((MyDecorator)userService1).TargetClass = new UserService();
            userService1.AddUser(user);
 
            Console.WriteLine("=============Castle.Core==============");
 
            ProxyGenerator generator = new ProxyGenerator();
            var u = generator.CreateInterfaceProxyWithTarget<IUserService>(new UserService(),new MyIntercept());
            u.AddUser(user);
 
 
 
            Console.ReadLine();
        }
    }
}

  这样就行了,看运行结果:

  综上,第三方使用相对简单,而且封装了好多方法,不仅仅以上的使用方式。 以下举例集成Autofac和Castle.Core在Asp.NetCore中的应用(用Asp.NetCore项目,是因为好多真实项目都是API或Web项目,所以比较符合实际),仅供给大家提供思路。如下:

  1. 首先我们创建一个Asp.NetCore项目,这里我创建的是API项目,正常运行即可,项目结构如下;

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

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

  3.模拟编写用户维护相关逻辑,代码如下:

  接口:

1
2
3
4
public interface IUserService
    {
        int AddUser(string strName, int nAge);
    }

  实现:

1
2
3
4
5
6
7
8
9
10
11
public class UserService : IUserService
   {
       /// <summary>
       /// 模拟新增用户,这里没有写数据处理层
       /// </summary>
       public int AddUser(string strName, int nAge)
       {
           Console.WriteLine("新增用户到数据库中");
           return 1;
       }
   }

  4. 编写拦截器逻辑,即代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
namespace WebAop.Aop
{
    public class UserAop : IInterceptor
    {    //关键所在,在执行方法前后进行相关逻辑处理
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("新增用户前进行其他处理");
 
            //调用原有方法
            invocation.Proceed();
 
            Console.WriteLine("新增用户后进行其他处理");
        }
    }
}

  5. 集成Autofac将用户维护服务这块进行注册到容器中:

  •   首先在Startup中增加方法,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void ConfigureContainer(ContainerBuilder builder)
        {
            //注册用户维护业务层
            var basePath = AppContext.BaseDirectory;
            var serviceDll = Path.Combine(basePath, "AopService.dll");
 
            if(!File.Exists(serviceDll))
            {
                throw new Exception("找不到程序集");
            }
            //注册AOP拦截器
            builder.RegisterType(typeof(UserAop));
            builder.RegisterAssemblyTypes(Assembly.LoadFrom(serviceDll))
                .AsImplementedInterfaces()
                .EnableInterfaceInterceptors()//开启切面,需要引入Autofac.Extras.DynamicProxy
                .InterceptedBy(typeof(UserAop));//指定拦截器,可以指定多个
        }
  •   然后在program中添加Autofac的工厂,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
 
namespace WebAop
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }
 
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                //需要引入Autofac.Extensions.DependencyInjection, 这里重要,不然Autofac不管用
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

  6. 增加UserController方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AopService.Interface;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
 
namespace WebAop.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        private IUserService _userService;
       <strong> //这里已经通过Autofac 注册过了,直接通过构造函数注入即可
        public UserController(IUserService userService)
        {
            _userService = userService;
        }</strong>
 
        [HttpGet]
       [Route("AddUser")]
        public IActionResult AddUser(string name,int age)
        {
           <strong> //正常调用用户新增操作
            _userService.AddUser(name, age);</strong>
            return Ok("Success!!");
        }
    }
}

  7. 运行走起,为了方便看见控制台打印,用项目启动方式进行运行,结果如下:

    直接在浏览器中输入http://localhost:5000/api/User/AddUser?name=sss&age=12,然后回车,然后看控制台打印:

  

总结:

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

Asp.NetCore 中Aop的应用的更多相关文章

  1. AutoMapper在asp.netcore中的使用

    # AutoMapper在asp.netcore中的使用  automapper 是.net 项目中针对模型之间转换映射的一个很好用的工具,不仅提高了开发的效率还使代码更加简洁,当然也是开源的,htt ...

  2. SignalR在Asp.NetCore中的使用

    SignalR简介 ASP.NET SignalR是为ASP.NET 开发人员提供的一个库,旨在为你的Web应用迅速简便的添加实时通信功能.这个Web通信功能是指:客户端可以实时从服务端代码拉取数据, ...

  3. 壹佰文章最全总结| 《关于ASP.NETCore的分享之路》

    学习路线图 (关于学习ASP.NET Core需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...

  4. asp.netcore 深入了解配置文件加载过程

    前言     配置文件中程序运行中,担当着不可或缺的角色:通常情况下,使用 visual studio 进行创建项目过程中,项目配置文件会自动生成在项目根目录下,如 appsettings.json, ...

  5. ASP.NETCore学习记录(一)

    ASP.NETCore学习记录(一) asp.net core介绍  Startup.cs  ConfigureServices  Configure  0. ASP.NETCore 介绍 ASP.N ...

  6. Asp.NetCore源码学习[2-1]:配置[Configuration]

    Asp.NetCore源码学习[2-1]:配置[Configuration] 在Asp. NetCore中,配置系统支持不同的配置源(文件.环境变量等),虽然有多种的配置源,但是最终提供给系统使用的只 ...

  7. Asp.NetCore Web开发之会话技术

    这节讲一下会话技术,首先了解一下什么是会话,会话是指浏览器打开到关闭的过程中,多次与服务器发送接收数据的过程. 由于HTTP是无状态协议,一次请求响应过后,产生的数据就随之释放了,可是在某些情况下,我 ...

  8. .netcore 中使用开源的AOP框架 AspectCore

    AspectCore Project 介绍 什么是AspectCore Project ? AspectCore Project 是适用于Asp.Net Core 平台的轻量级 Aop(Aspect- ...

  9. asp.netMVC中使用aop进行关注点分离

    资源地址:https://stackoverflow.com/questions/23244400/aspect-oriented-programming-in-asp-net-mvc 从页面复制过来 ...

随机推荐

  1. python 模拟点击微信

    from PyQt5 import QtCore,QtWidgets import win32gui, win32api, win32con # 调用win32api的模拟点击功能实现ctrl+v粘贴 ...

  2. C语言:const详解

    希望定义这样一种变量,它的值不能被改变,在整个作用域中都保持固定.例如,用一个变量来表示班级的最大人数,或者表示缓冲区的大小.为了满足这一要求,可以使用const关键字对变量加以限定:const in ...

  3. 一行代码打印python之禅

    就这一句: import this 输出: The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is be ...

  4. [刘阳Java]_MyBatis_其他方式来实现多表查询的操作_第9讲

    MyBatis其他方式来实现多表查询的操作 利用Java中的集合框架(List,Map) 其中List存储多个查询返回的记录 Map查询返回字段,同时记录表中一条数据 <?xml version ...

  5. tcpdump软件使用

    tcpdump是一个抓包工具, -w 选项是把抓到的包写到二进制文件中,一般扩展名是.cap或.dmp,但tcpdump程序创建文件时并不添加扩展名,可自己指定. -i 是指定要抓包的interfac ...

  6. Appium - monkey自定义脚本实践(四)

    monkey自定义脚本实践 一.获取元素坐标点位置 二.Monkey脚本API简介 常规Monkey测试执行的是随机的事件流,但如果只是想让Monkey测试某个特定场景这时候就需要用到自定义脚本了,M ...

  7. 一行代码让matplotlib图表变高大上

    1 简介 matplotlib作为Python生态中最流行的数据可视化框架,虽然功能非常强大,但默认样式比较简陋,想要制作具有简洁商务风格的图表往往需要编写众多的代码来调整各种参数. 而今天要为大家介 ...

  8. 在LinuxMint 17 MATE中安装NVIDIA显卡驱动

    第一步:在Linux系统中安装Nvidia显卡驱动需要关闭X Server. 打开终端,进入ROOT权限,执行以下命令 $ sudo service mdm stop 此时将会把X Server关闭, ...

  9. Altium Designer 21.x中文版安装破解教程

    Altium Designer 21.x是一款优秀的PCB设计工具,可以原理图设计.电路仿真.PCB绘制编辑.拓扑逻辑自动布线.信号完整性分析和设计输出等功能,为设计者提供了全新的设计解决方案,提高设 ...

  10. Vue--el-menu 的自动跳转功能与自己的click事件冲突

    一\先看elementUI说明 项目实际 此时点击活导航时以 index 作为 path 进行路由跳转 那么此时不要onclik事件了 如果此时有在有click 就