Asp.NetCore 中Aop的應用


前言

  其實好多項目中,做一些數據攔截、數據緩存都有Aop的概念,只是實現方式不一樣;之前大家可能都會利用過濾器來實現Aop的功能,如果是Asp.NetCore的話,也可能會使用中間件; 而這種實現方式都是在請求過程中進行攔截,如果我們想在服務層中做切面的話,那種方式顯然不好使了,需要用到“真正的Aop”。

直接開始

  其實我們常說的“真正的Aop”其實就是動態代理,理論知識我這里就不記錄了,自己也寫不好,大家自行找度娘,我們這直接上代碼:

  正常搭建一個控制台項目,目錄結構如下:

 

   這里就是模擬一個簡單的用戶維護,代碼內容如下:

    定義Model

public class User
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    定義接口

public interface IUserService
    {
        bool AddUser(User user);
    }

    實現接口

public class UserService : IUserService
    {
        public bool AddUser(User user)
        {
            Console.WriteLine("用戶添加成功");
            return true;
        }
    }

  main方法

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. 增加一個類,進行業務操作;

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Aop
{
    public class MyDecorator : DispatchProxy
    {
        //具體類型
        public object TargetClass { get; set; }
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            Console.WriteLine("增加用戶前執行業務");

            //調用原有方法
            targetMethod.Invoke(TargetClass, args);

            Console.WriteLine("增加用戶后執行業務");
            
            return true;
        }
    }
}

  優化 Main()函數的代碼

 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. 新增攔截器類,做業務擴展;

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的用法

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.模擬編寫用戶維護相關邏輯,代碼如下:

  接口:

public interface IUserService
    {
        int AddUser(string strName, int nAge);
    }

  實現:

 public class UserService : IUserService
    {
        /// <summary>
        /// 模擬新增用戶,這里沒有寫數據處理層
        /// </summary>
        public int AddUser(string strName, int nAge)
        {
            Console.WriteLine("新增用戶到數據庫中");
            return 1;
        }
    }

  4. 編寫攔截器邏輯,即代理:

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中增加方法,如下:
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的工廠,如下:
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方法,如下:

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;
        //這里已經通過Autofac 注冊過了,直接通過構造函數注入即可
        public UserController(IUserService userService)
        {
            _userService = userService;
        }

        [HttpGet]
       [Route("AddUser")]
        public IActionResult AddUser(string name,int age)
        {
            //正常調用用戶新增操作
            _userService.AddUser(name, age);
            return Ok("Success!!");
        }
    }
}

  7. 運行走起,為了方便看見控制台打印,用項目啟動方式進行運行,結果如下:

    直接在瀏覽器中輸入http://localhost:5000/api/User/AddUser?name=sss&age=12,然后回車,然后看控制台打印:

  

 

 

總結:

  AOP在做一些業務前置或后置處理上時很有用的,使用比較靈活,無需修改原有代碼邏輯,比起修改原有代碼維護相對好多啦!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM