您的位置:首頁 > 軟件教程 > 教程 > Asp .Net Core 系列:基于 Castle DynamicProxy + Autofac 實踐 AOP 以及實現(xiàn)事務、用戶填充功能

Asp .Net Core 系列:基于 Castle DynamicProxy + Autofac 實踐 AOP 以及實現(xiàn)事務、用戶填充功能

來源:好特整理 | 時間:2024-07-05 08:57:14 | 閱讀:59 |  標簽: T MIC Net Cast S C XY 用戶   | 分享到:

目錄什么是 AOP ?.Net Core 中 有哪些 AOP 框架?基于 Castle DynamicProxy 實現(xiàn) AOPIOC中使用 Castle DynamicProxy實現(xiàn)事務管理實現(xiàn)用戶自動填充 什么是 AOP ? AOP(Aspect-Oriented Programming,面向切面

什么是 AOP ?

AOP(Aspect-Oriented Programming,面向切面編程)是一種編程范式,旨在通過將橫切關注點(cross-cutting concerns)從主要業(yè)務邏輯中分離出來,以提高代碼的模塊化性、可維護性和復用性。

在傳統(tǒng)的面向?qū)ο缶幊讨校覀兺ǔMㄟ^類和對象來組織和實現(xiàn)功能。然而,某些功能,如日志記錄、事務管理、安全性檢查等,可能會跨越多個對象和模塊,這種跨越稱為橫切關注點。AOP 的核心思想是將這些橫切關注點從業(yè)務邏輯中分離出來,通過特定的機制將它們應用到代碼中,而不是通過直接修改業(yè)務邏輯來實現(xiàn)。

.Net Core 中 有哪些 AOP 框架?

PostSharp(收費)

PostSharp是一個功能強大的AOP框架,它通過編譯器插件的形式集成到Visual Studio中。PostSharp支持編譯時AOP(通過C#特性應用切面),并提供了豐富的切面類型,包括方法攔截、屬性訪問攔截、異常處理等。它還提供了商業(yè)支持和豐富的文檔。

Castle DynamicProxy

Castle DynamicProxy是Castle項目的一部分,它允許開發(fā)者在運行時動態(tài)創(chuàng)建代理類,這些代理類可以攔截對目標對象的調(diào)用,并在調(diào)用前后執(zhí)行自定義邏輯。雖然它本身不是一個完整的AOP框架,但它經(jīng)常被用作構(gòu)建AOP解決方案的基礎。

AspectCore Framework

AspectCore 是一個開源的 AOP 框架,專為 .NET Core 設計。它提供了基于動態(tài)代理的運行時切面和方法攔截機制,支持常見的切面編程需求,如日志、緩存、事務等。

基于 Castle DynamicProxy 實現(xiàn) AOP

1. 安裝Castle.Core NuGet包

Install-Package Castle.Core

2. 定義接口和類

假設你有一個接口和一個實現(xiàn)了該接口的類,你想要攔截這個類的方法調(diào)用。

public interface IMyService  
{  
    void PerformAction();  
}   
public class MyService : IMyService  
{  
    public void PerformAction()  
    {  
        Console.WriteLine("Action performed.");  
    }  
}

3. 創(chuàng)建攔截器

接下來,你需要創(chuàng)建一個攔截器類,該類將實現(xiàn) IInterceptor 接口。在這個接口的實現(xiàn)中,你可以定義在調(diào)用目標方法之前和之后要執(zhí)行的邏輯。

using Castle.DynamicProxy;  
  
public class MyInterceptor : IInterceptor  
{  
    public void Intercept(IInvocation invocation)  
    {  
        // 在調(diào)用目標方法之前執(zhí)行的邏輯  
        Console.WriteLine("Before method: " + invocation.Method.Name);  
  
        // 調(diào)用目標方法  
        invocation.Proceed();  
  
        // 在調(diào)用目標方法之后執(zhí)行的邏輯  
        Console.WriteLine("After method: " + invocation.Method.Name);  
    }  
}

4. 創(chuàng)建代理并調(diào)用方法

最后,你需要使用 ProxyGenerator 類來創(chuàng)建 MyService 的代理實例,并指定攔截器。然后,你可以像使用普通對象一樣調(diào)用代理的方法,但攔截器中的邏輯會在調(diào)用發(fā)生時執(zhí)行。

using Castle.DynamicProxy;  
  
public class Program  
{  
    public static void Main(string[] args)  
    {  
        var generator = new ProxyGenerator();  
        var interceptor = new MyInterceptor();  
  
        // 創(chuàng)建MyService的代理實例,并指定攔截器  
        var proxy = generator.CreateInterfaceProxyWithTarget(  
            new MyService(), interceptor);  
  
        // 調(diào)用代理的方法,攔截器中的邏輯將被執(zhí)行  
        proxy.PerformAction();  
    }  
}

注意,上面的示例使用了接口代理( CreateInterfaceProxyWithTarget ),這意味著你的目標類必須實現(xiàn)一個或多個接口。如果你想要代理一個類而不是接口,你可以使用 CreateClassProxyWithTarget 方法(但這通常用于需要代理非虛方法或字段的場景,且要求目標類是可繼承的)。

IOC中使用 Castle DynamicProxy

由于IOC容器(如Microsoft的 IServiceCollection IServiceProvider )通常不直接支持AOP,所以用 Autofac
1. 安裝必要的 NuGet 包

首先,確保你的項目中安裝了以下 NuGet 包:

Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection
Install-Package Autofac.Extras.DynamicProxy
Install-Package Castle.Core

2. 創(chuàng)建服務接口和實現(xiàn)類

    public class User
    {
        public long Id { get; set; }

        public string Name { get; set; }

        public long CreateUserId { get; set; }

        public string CreateUserName { get; set; }

        public DateTime CreateTime { get; set; }

        public long UpdateUserId { get; set; }

        public string UpdateUserName { get; set; }

        public DateTime UpdateTime { get; set; }
    }    

    public interface IUserService
    {
        void Test();

        Task TaskTest();

        void Add(User user);

       void Update(User user);
    }


    public class UserService : IUserService
    {
        public void Test()
        {
            Console.WriteLine("Test");
        }

        public async Task TaskTest()
        {
            await Console.Out.WriteLineAsync("TaskTest");
            return 1;
        }

        public void Add(User user)
        {
            Console.WriteLine(user.CreateUserId);
            Console.WriteLine(user.CreateUserName);
        }

        public void Update(User user)
        {
            Console.WriteLine(user.UpdateUserId);
            Console.WriteLine(user.UpdateUserName);
        }
    }

    [ApiController]
    [Route("[controller]")]
    public class UserController : ControllerBase
    {
        readonly IUserService _userService;

        public UserController(IUserService userService)
        {
            _userService = userService;
        }        

        [HttpGet]
        [Route("/taskTest")]
        public async Task TaskTest()
        {
            await _userService.TaskTest();
            return "ok";
        }

        [HttpGet]
        [Route("/test")]
        public string Test()
        {
            _userService.Test();
            return "ok";
        }

        [HttpGet]
        [Route("/add")]
        public string Add()
        {
            _userService.Add(new Model.User { Name = "張三" });
            return "ok";
        }


        [HttpGet]
        [Route("/update")]
        public string Update()
        {
            _userService.Update(new Model.User { Name = "張三" });
            return "ok";
        }
    }

3. 創(chuàng)建攔截器類

創(chuàng)建一個實現(xiàn) IInterceptor 接口的攔截器類 LoggingInterceptor ,用于攔截方法調(diào)用并添加日志記錄:

public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine($"Before executing: {invocation.Method.Name}");

        invocation.Proceed(); // 調(diào)用原始方法

        Console.WriteLine($"After executing: {invocation.Method.Name}");
    }
}

4. 配置 Autofac 容器

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //使用Autofac
                        .ConfigureContainer(autofacBuilder =>
                        {
                       
                            autofacBuilder.RegisterType();
                                             
                            autofacBuilder.RegisterType().As    ().SingleInstance().AsImplementedInterfaces()    
                            .EnableInterfaceInterceptors() // 啟用接口攔截器
                            .InterceptedBy(typeof(LoggingInterceptor)); //指定攔截器
                        });

與Autofac集成時,配置攔截器主要有兩種方式

使用 InterceptAttribute 特性

這種方式通過在接口或類上添加 [Intercept(typeof(YourInterceptor))] 特性來指定攔截器。然后,在Autofac注冊時,啟用接口或類的攔截器。(通常不推薦在類上直接添加,因為這會使類與Autofac緊密耦合)

 [Intercept(typeof(UserAutoFillInterceptor))]
 public class UserService : IUserService
{  
     public void Test()
     {
        Console.WriteLine("Test");
     } 
}

autofacBuilder.RegisterType().As().EnableInterfaceInterceptors() // 啟用接口攔截器

使用 InterceptedBy() 方法

這種方式不依賴于 [Intercept] 特性,而是在注冊服務時直接使用 InterceptedBy() 方法來指定攔截器。

                            autofacBuilder.RegisterType().As()    
                            .EnableInterfaceInterceptors() // 啟用接口攔截器
                            .InterceptedBy(typeof(LoggingInterceptor)); //指定攔截器

實現(xiàn)事務管理

攔截器基類

    /// 
    /// 攔截基類
    /// 
    /// 
    public abstract class BaseInterceptor : IInterceptor
    {
        protected readonly ILogger _logger;
        public BaseInterceptor(ILogger logger)
        {
            _logger = logger;
        }

        /// 
        /// 攔截方法
        /// 
        /// 
        public virtual void Intercept(IInvocation invocation)
        {
            try
            {
                Method = invocation.MethodInvocationTarget ?? invocation.Method;
                InterceptHandle(invocation);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                throw ex;
            }         
        }

        /// 
        /// 攔截處理
        /// 
        /// 
        public abstract void InterceptHandle(IInvocation invocation);

        protected MethodInfo Method{ get; set; }

        public static bool IsAsyncMethod(MethodInfo method)
        {
            return (method.ReturnType == typeof(Task) ||
                (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
            );
        }
}

事務特性:用來判斷是否需要事務管理的

    /// 
    /// 事務特性
    /// 
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
    public class TransactionalAttribute : Attribute
    {
        public TransactionalAttribute()
        {
            Timeout = 60;
        }

        /// 
        /// 
        /// 
        public int Timeout { get; set; }

        /// 
        /// 事務隔離級別
        /// 
        public IsolationLevel IsolationLevel { get; set; }

        /// 
        /// 事務傳播方式
        /// 
        public Propagation Propagation { get; set; }
    }

    /// 
    /// 事務傳播方式
    /// 
    public enum Propagation
    {
        /// 
        /// 默認:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中。
        /// 
        Required = 0,

        /// 
        /// 使用當前事務,如果沒有當前事務,就拋出異常
        /// 
        Mandatory = 1,

        /// 
        /// 以嵌套事務方式執(zhí)行
        /// 
        Nested = 2,
    }

事務攔截器:處理事務的

    /// 
    /// 事務攔截器
    /// 
    public class TransactionalInterceptor : BaseInterceptor
    {
        public TransactionalInterceptor(ILogger logger) : base(logger)
        {

        }

        public override void InterceptHandle(IInvocation invocation)
        {
            
            if (Method.GetCustomAttribute(true) == null && Method.DeclaringType?.GetCustomAttribute(true) == null)
            {
                invocation.Proceed();
            }
            else
            {
                try
                {
                    Console.WriteLine("開啟事務");

                    //執(zhí)行方法
                    invocation.Proceed();

                    // 異步獲取異常,先執(zhí)行
                    if (IsAsyncMethod(invocation.Method))
                    {
                        var result = invocation.ReturnValue;
                        if (result is Task)
                        {
                            Task.WaitAll(result as Task);
                        }
                    }

                    Console.WriteLine("提交事務");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("回滾事務");
                    _logger.LogError(ex, ex.Message);
                    throw ex;
                }
            }
        }
    }

接口上加入事務特性

    //[Transactional]
    public class UserService : IUserService
    {

        [Transactional]
        public void Test()
        {
            Console.WriteLine("Test");
        }
    }

注入IOC

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                        .ConfigureContainer(autofacBuilder =>
                        {
                            autofacBuilder.RegisterType();                                      
                            autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces()
                            .EnableInterfaceInterceptors()
                            .InterceptedBy(typeof(TransactionalInterceptor));
                        });

測試

Asp .Net Core 系列:基于 Castle DynamicProxy + Autofac 實踐 AOP 以及實現(xiàn)事務、用戶填充功能

實現(xiàn)用戶自動填充

上下戶用戶

    public interface IHttpContextUser
    {
         long UserId { get; }

         string UserName { get;}
    }


    public class HttpContextUser : IHttpContextUser
    {
        private readonly IHttpContextAccessor _accessor;
        public HttpContextUser(IHttpContextAccessor accessor)
        {
            _accessor = accessor;
        }
        public long UserId
        {
            get
            {
                return 1; //這里暫時是寫死的
                if (int.TryParse(_accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Sid), out var userId))
                {
                    return userId;
                }
                return default;
            }
        }

        public string UserName
        {
            get
            {
                return "admin"; //這里暫時是寫死的
                return _accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name) ?? "";
            }
        }
    }


注入IOC

           builder.Services.AddHttpContextAccessor();
           builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                        .ConfigureContainer(autofacBuilder =>
                        {
                       
                            autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces();
                            autofacBuilder.RegisterType();
                       
                       
                            autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces()
                            .EnableInterfaceInterceptors()
                            .InterceptedBy(typeof(UserAutoFillInterceptor));
                        });

用戶自動攔截器:處理用戶填充的

    /// 
    /// 用戶自動填充攔截器
    /// 
    public class UserAutoFillInterceptor : BaseInterceptor
    {
        private readonly IHttpContextUser _user;
        public UserAutoFillInterceptor(ILogger logger,IHttpContextUser user) : base(logger)
        {
            _user = user;
        }

        public override void InterceptHandle(IInvocation invocation)
        {
            //對當前方法的特性驗證
            if (Method.Name?.ToLower() == "add" || Method.Name?.ToLower() == "update")
            {
                if (invocation.Arguments.Length == 1 && invocation.Arguments[0].GetType().IsClass)
                {
                    dynamic argModel = invocation.Arguments[0];
                    var getType = argModel.GetType();
                    if (Method.Name?.ToLower() == "add")
                    {
                        if (getType.GetProperty("CreateUserId") != null)
                        {
                            argModel.CreateUserId = _user.UserId;
                        }
                        if (getType.GetProperty("CreateUserName") != null)
                        {
                            argModel.CreateUserName = _user.UserName;
                        }
                        if (getType.GetProperty("CreateTime") != null)
                        {
                            argModel.CreateTime = DateTime.Now;
                        }
                     
                    }
                    if (getType.GetProperty("UpdateUserId") != null)
                    {
                        argModel.UpdateUserId = _user.UserId;
                    }
                    if (getType.GetProperty("UpdateUserName") != null)
                    {
                        argModel.UpdateUserName = _user.UserName;
                    }
                    if (getType.GetProperty("UpdateTime") != null)
                    {
                        argModel.UpdateTime = DateTime.Now;
                    }
                   
                    }
                invocation.Proceed();
            }
            else
            {
                invocation.Proceed();
            }
        }
    }

測試

Asp .Net Core 系列:基于 Castle DynamicProxy + Autofac 實踐 AOP 以及實現(xiàn)事務、用戶填充功能

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認同期限觀點或證實其描述。

Cast 0.1
Cast 0.1
類型:休閑益智  運營狀態(tài):正式運營  語言:中文   

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動

《Cast》是網(wǎng)易游戲?qū)W院開發(fā)的一款經(jīng)典黑白畫風的解密手游,游戲以平臺跳躍的方式,在每個關卡中完成不同

相關視頻攻略

更多

掃二維碼進入好特網(wǎng)手機版本!

掃二維碼進入好特網(wǎng)微信公眾號!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]

湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)