微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Asp.NetCore 中Aop的应用

前言

  其实好多项目中,做一些数据拦截、数据缓存都有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 targetmethodobject[] 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将用户维护服务这块进行注册到容器中:

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

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐