LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

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

freeflydom
2024年9月13日 9:24 本文熱度 989

什么是 AOP ?

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

在傳統的面向對象編程中,我們通常通過類和對象來組織和實現功能。然而,某些功能,如日志記錄、事務管理、安全性檢查等,可能會跨越多個對象和模塊,這種跨越稱為橫切關注點。AOP 的核心思想是將這些橫切關注點從業務邏輯中分離出來,通過特定的機制將它們應用到代碼中,而不是通過直接修改業務邏輯來實現。

.Net Core 中 有哪些 AOP 框架?

PostSharp(收費)

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

Castle DynamicProxy

Castle DynamicProxy是Castle項目的一部分,它允許開發者在運行時動態創建代理類,這些代理類可以攔截對目標對象的調用,并在調用前后執行自定義邏輯。雖然它本身不是一個完整的AOP框架,但它經常被用作構建AOP解決方案的基礎。

AspectCore Framework

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

基于 Castle DynamicProxy 實現 AOP

1. 安裝Castle.Core NuGet包

Install-Package Castle.Core


2. 定義接口和類

假設你有一個接口和一個實現了該接口的類,你想要攔截這個類的方法調用。

public interface IMyService  

{  

    void PerformAction();  

}   

public class MyService : IMyService  

{  

    public void PerformAction()  

    {  

        Console.WriteLine("Action performed.");  

    }  

}

3. 創建攔截器

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

using Castle.DynamicProxy;  

  

public class MyInterceptor : IInterceptor  

{  

    public void Intercept(IInvocation invocation)  

    {  

        // 在調用目標方法之前執行的邏輯  

        Console.WriteLine("Before method: " + invocation.Method.Name);  

  

        // 調用目標方法  

        invocation.Proceed();  

  

        // 在調用目標方法之后執行的邏輯  

        Console.WriteLine("After method: " + invocation.Method.Name);  

    }  

}

4. 創建代理并調用方法

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

using Castle.DynamicProxy;  

  

public class Program  

{  

    public static void Main(string[] args)  

    {  

        var generator = new ProxyGenerator();  

        var interceptor = new MyInterceptor();  

  

        // 創建MyService的代理實例,并指定攔截器  

        var proxy = generator.CreateInterfaceProxyWithTarget<IMyService>(  

            new MyService(), interceptor);  

  

        // 調用代理的方法,攔截器中的邏輯將被執行  

        proxy.PerformAction();  

    }  

}

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

IOC中使用 Castle DynamicProxy

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

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

Install-Package Autofac

Install-Package Autofac.Extensions.DependencyInjection

Install-Package Autofac.Extras.DynamicProxy

Install-Package Castle.Core

2. 創建服務接口和實現類

    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<int> TaskTest();


        void Add(User user);


       void Update(User user);

    }



    public class UserService : IUserService

    {

        public void Test()

        {

            Console.WriteLine("Test");

        }


        public async Task<int> 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<string> 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. 創建攔截器類

創建一個實現 IInterceptor 接口的攔截器類 LoggingInterceptor,用于攔截方法調用并添加日志記錄:

public class LoggingInterceptor : IInterceptor

{

    public void Intercept(IInvocation invocation)

    {

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


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


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

    }

}

4. 配置 Autofac 容器

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //使用Autofac

                        .ConfigureContainer<ContainerBuilder>(autofacBuilder =>

                        {

                       

                            autofacBuilder.RegisterType<LoggingInterceptor>();

                                             

                            autofacBuilder.RegisterType<UserService>().As<IUserService>    ().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<UserService>().As<IUserService>().EnableInterfaceInterceptors() // 啟用接口攔截器

使用 InterceptedBy() 方法

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

                            autofacBuilder.RegisterType<UserService>().As<IUserService>()    

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

                            .InterceptedBy(typeof(LoggingInterceptor)); //指定攔截器

實現事務管理

攔截器基類

    /// <summary>

    /// 攔截基類

    /// </summary>

    /// <typeparam name="T"></typeparam>

    public abstract class BaseInterceptor<T> : IInterceptor

    {

        protected readonly ILogger<T> _logger;

        public BaseInterceptor(ILogger<T> logger)

        {

            _logger = logger;

        }


        /// <summary>

        /// 攔截方法

        /// </summary>

        /// <param name="invocation"></param>

        public virtual void Intercept(IInvocation invocation)

        {

            try

            {

                Method = invocation.MethodInvocationTarget ?? invocation.Method;

                InterceptHandle(invocation);

            }

            catch (Exception ex)

            {

                _logger.LogError(ex, ex.Message);

                throw ex;

            }         

        }


        /// <summary>

        /// 攔截處理

        /// </summary>

        /// <param name="invocation"></param>

        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<>))

            );

        }

}

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

    /// <summary>

    /// 事務特性

    /// </summary>

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]

    public class TransactionalAttribute : Attribute

    {

        public TransactionalAttribute()

        {

            Timeout = 60;

        }


        /// <summary>

        /// 

        /// </summary>

        public int Timeout { get; set; }


        /// <summary>

        /// 事務隔離級別

        /// </summary>

        public IsolationLevel IsolationLevel { get; set; }


        /// <summary>

        /// 事務傳播方式

        /// </summary>

        public Propagation Propagation { get; set; }

    }


    /// <summary>

    /// 事務傳播方式

    /// </summary>

    public enum Propagation

    {

        /// <summary>

        /// 默認:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中。

        /// </summary>

        Required = 0,


        /// <summary>

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

        /// </summary>

        Mandatory = 1,


        /// <summary>

        /// 以嵌套事務方式執行

        /// </summary>

        Nested = 2,

    }


事務攔截器:處理事務的

    /// <summary>

    /// 事務攔截器

    /// </summary>

    public class TransactionalInterceptor : BaseInterceptor<TransactionalInterceptor>

    {

        public TransactionalInterceptor(ILogger<TransactionalInterceptor> logger) : base(logger)

        {


        }


        public override void InterceptHandle(IInvocation invocation)

        {

            

            if (Method.GetCustomAttribute<TransactionalAttribute>(true) == null && Method.DeclaringType?.GetCustomAttribute<TransactionalAttribute>(true) == null)

            {

                invocation.Proceed();

            }

            else

            {

                try

                {

                    Console.WriteLine("開啟事務");


                    //執行方法

                    invocation.Proceed();


                    // 異步獲取異常,先執行

                    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<ContainerBuilder>(autofacBuilder =>

                        {

                            autofacBuilder.RegisterType<TransactionalInterceptor>();                                      

                            autofacBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().AsImplementedInterfaces()

                            .EnableInterfaceInterceptors()

                            .InterceptedBy(typeof(TransactionalInterceptor));

                        });


測試

實現用戶自動填充

上下戶用戶

    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<ContainerBuilder>(autofacBuilder =>

                        {

                       

                            autofacBuilder.RegisterType<HttpContextUser>().As<IHttpContextUser>().SingleInstance().AsImplementedInterfaces();

                            autofacBuilder.RegisterType<UserAutoFillInterceptor>();

                       

                       

                            autofacBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().AsImplementedInterfaces()

                            .EnableInterfaceInterceptors()

                            .InterceptedBy(typeof(UserAutoFillInterceptor));

                        });


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

    /// <summary>

    /// 用戶自動填充攔截器

    /// </summary>

    public class UserAutoFillInterceptor : BaseInterceptor<UserAutoFillInterceptor>

    {

        private readonly IHttpContextUser _user;

        public UserAutoFillInterceptor(ILogger<UserAutoFillInterceptor> 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();

            }

        }

    }


測試



該文章在 2024/9/13 9:24:52 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved

黄频国产免费高清视频,久久不卡精品中文字幕一区,激情五月天AV电影在线观看,欧美国产韩国日本一区二区
亚洲成Av人片乱码午夜 | 日本大片免a费观看视频 | 日韩精品视频网站 | 日本高新在线亚洲视频看看 | 热久久99精品综合久久 | 色综合天天综合高清网国产在线 |