菜渣开源一个基于 EMIT 的 AOP 库(.NET Core)

目录

Nuget 库地址:https://www.nuget.org/packages/CZGL.AOP/

Github 库地址:https://github.com/whuanle/CZGL.AOP

CZGL.AOP 是 基于 EMIT 编写的 一个简朴轻量的AOP框架,支持非侵入式署理,支持.NET Core/ASP.NET Core,以及支持多种依赖注入框架。

1,快速入门

CZGL.AOP 使用比较简朴,你只需要使用 [Interceptor] 特征符号需要署理的类型,然后使用继续 ActionAttribute 的特征符号要被署理的方式或属性。

1.1 继续 ActionAttribute 特征

ActionAttribute 是用于署理方式或属性的特征符号,不能直接使用,需要继续后重写方式。

示例如下:

    public class LogAttribute : ActionAttribute
    {
        public override void Before(AspectContext context)
        {
            Console.WriteLine("执行前");
        }

        public override object After(AspectContext context)
        {
            Console.WriteLine("执行后");
            if (context.IsMethod)
                return context.MethodResult;
            else if (context.IsProperty)
                return context.PropertyValue;
            return null;
        }
    }

Before 会在被署理的方式执行前或被署理的属性挪用时生效,你可以通过 AspectContext 上下文,获取、修改通报的参数。

After 在方式执行后或属性挪用时生效,你可以通过上下文获取、修改返回值。

1.2 符号署理类型

在被署理的类型中,使用 [Interceptor] 特征来符号,在需要署理的方式中,使用 继续了 ActionAttribute 的特征来符号。

此方式是侵入式的,需要在编译前完成。

[Interceptor]
public class Test : ITest
{
    [Log] public virtual string A { get; set; }
    [Log]
    public virtual void MyMethod()
    {
        Console.WriteLine("运行中");
    }
}

注重的是,一个方式或属性只能设置一个阻挡器。

2,若何建立署理类型

CZGL.AOP 有多种天生署理类型的方式,下面先容简朴的方式。

请预先建立如下代码:

    public class LogAttribute : ActionAttribute
    {
        public override void Before(AspectContext context)
        {
            Console.WriteLine("执行前");
        }

        public override object After(AspectContext context)
        {
            Console.WriteLine("执行后");
            if (context.IsMethod)
                return context.MethodResult;
            else if (context.IsProperty)
                return context.PropertyValue;
            return null;
        }
    }

    public interface ITest
    {
        void MyMethod();
    }

    [Interceptor]
    public class Test : ITest
    {
        [Log] public virtual string A { get; set; }
        public Test()
        {
            Console.WriteLine("组织函数没问题");
        }
        [Log]
        public virtual void MyMethod()
        {
            Console.WriteLine("运行中");
        }
    }

2.1 通过API直接建立

通过 CZGL.AOP 中的 AopInterceptor 类,你可以天生署理类型。

示例如下:

            ITest test1 = AopInterceptor.CreateProxyOfInterface<ITest, Test>();
            Test test2 = AopInterceptor.CreateProxyOfClass<Test>();
            test1.MyMethod();
            test2.MyMethod();

CreateProxyOfInterface 通过接口建立署理类型;CreateProxyOfClass 通过类建立署理类型;

默认挪用的是无参组织函数。

2,建立署理类型

通过API

你可以参考源码解决方案

中的 ExampleConsole 项目。

若是要直接使用 AopInterceptor.CreateProxyOfInterfaceAopInterceptor.CreateProxyOfClass 方式,通过接口或类来建立署理类型。

        ITest test1 = AopInterceptor.CreateProxyOfInterface<ITest, Test>();
        Test test2 = AopInterceptor.CreateProxyOfClass<Test>();

若是要指定实例化的组织函数,可以这样:

            // 指定组织函数
            test2 = AopInterceptor.CreateProxyOfClass<Test>("aaa", "bbb");
            test2.MyMethod();

通过 Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.DependencyInjection 是 .NET Core/ASP.NET Core 默认的依赖注入容器。

若是需要支持 ASP.NET Core 中使用 AOP,你可以在 Nuget 包中安装 CZGL.AOP.MEDI

若是你在控制台下使用 Microsoft.Extensions.DependencyInjection,你可以使用名为 BuildAopProxyIServiceCollection 拓展方式来为容器中的类型,天生署理类型。

示例如下:

            IServiceCollection _services = new ServiceCollection();
            _services.AddTransient<ITest, Test>();
            var serviceProvider = _services.BuildAopProxy().BuildServiceProvider();
            serviceProvider.GetService<ITest>();
            return serviceProvider;

你可以参考源码解决方案中的 ExampleMEDI 项目。

若是你要在 ASP.NET Core 中使用,你可以在 Startup 中,ConfigureServices 方式的最后一行代码使用 services.BuildAopProxy();

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.BuildAopProxy();
        }

还可以在 ProgramIHostBuilder 中使用 .UseServiceProviderFactory(new AOPServiceProxviderFactory()) 来设置使用 CZGL.AOP。

Java并发编程(05):悲观锁和乐观锁机制

示例:

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AOPServiceProxviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

可以参考解决方案中的 ExampleConsoleExampleWebMEDI 两个项目。

你不必忧郁引入 CZGL.AOP 后,使用依赖注入会使程序变慢或者损坏容器中的原有属性。CZGL.AOP 只会在建立容器时处置需要被署理的类型,不会影响容器中的服务,也不会滋扰到依赖注入的执行。

通过 Autofac

若是需要在 Autofac 中使用 AOP,则需要引用 CZGL.AOP.Autofac 包。

若是你在控制台程序中使用 Autofac,则可以在 Build() 后面使用 BuildAopProxy()

            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Test>().As<ITest>();
            var container = builder.Build().BuildAopProxy();

            using (ILifetimeScope scope = container.BeginLifetimeScope())
            {
                // 获取实例
                ITest myService = scope.Resolve<ITest>();
                myService.MyMethod();
            }

            Console.ReadKey();
        }

要注重的是,在已经完成的组件注册建立一个新的容器后,才气挪用 BuildAopProxy() 方式,

这样针对一个新的容器你可以思量是否需要对容器中的组件举行署理。

若是在 ASP.NET Core 中使用 Autofac,你需要在 Program 类的 IHostBuilder 中使用:

.UseServiceProviderFactory(new AutofacServiceProviderFactory())

若是需要署理已经注册的组件,则将其替换为:

 .UseServiceProviderFactory(new CZGL.AOP.Autofac.AOPServiceProxviderFactory())

请参考 源码解决方案中的 ExampleAutofacExampleWebAutofac 两个项目。

3,深入使用

署理类型

要被署理的类型,需要使用 [Interceptor]来符号,例如:

    [Interceptor]
    public class Test : ITest
    {
    }

支持泛型类型。

被署理的类型必须是可被继续的。

类型的组织函数没有限制,你可以随意编写。

在使用 API 建立署理类型而且实例化时,你可以指定使用哪个组织函数。

例如:

			string a="",b="",c="";
			ITest test1 = AopInterceptor.CreateProxyOfInterface<ITest, Test>(a,b,c);

API 会凭据参数的若干以及参数的类型自动寻找合适的组织函数。

方式、属性署理

为了署理方式或属性,你需要继续 ActionAttribute 特征,然后为方式或属性符号此特征,而且将方式或属性设置为 virtual

一个类型中的差别方式,可以使用差别的阻挡器。

        [Log1]
        public virtual void MyMethod1(){}
        
        [Log2]
        public virtual void MyMethod2(){}

对于属性,可以在属性上直接使用特征,或者只在 get 或 set 组织器使用。

        [Log] public virtual string A { get; set; }
        
        // 或
        public virtual string A { [Log] get; set; }
        
        // 或
        public virtual string A { get; [Log] set; }

若是在属性上使用特征,相当于 [Log] get; [Log] set;

上下文

一个简朴的方式或属性阻挡符号是这样的:

    public class LogAttribute : ActionAttribute
    {
        public override void Before(AspectContext context)
        {
            Console.WriteLine("执行前");
        }

        public override object After(AspectContext context)
        {
            Console.WriteLine("执行后");
            if (context.IsMethod)
                return context.MethodResult;
            else if (context.IsProperty)
                return context.PropertyValue;
            return null;
        }
    }

AspectContext 的属性说明如下:

字段 说明
Type 当前被署理类型天生的署理类型
ConstructorParamters 类型被实例化时使用的组织函数的参数,若是组织函数没有参数,则 MethodValues.Length = 0,而不是 MethodValues 为 null。
IsProperty 当前阻挡的是属性
PropertyInfo 当前被执行的属性的信息,可为 null。
PropertyValue 但挪用的是属性时,返回 get 的效果或 set 的 value 值。
IsMethod 当前阻挡的是方式
MethodInfo 当前方式的信息
MethodValues 方式被挪用时通报的参数,若是此方式没有参数,则 MethodValues.Length = 0,而不是 MethodValues 为 null
MethodResult 方式执行返回的效果(若是有)

阻挡方式或属性的参数

通过上下文,你可以修改方式或属性的参数以及阻挡返回效果:

    public class LogAttribute : ActionAttribute
    {
        public override void Before(AspectContext context)
        {
            // 阻挡并修改方式的参数
            for (int i = 0; i < context.MethodValues.Length; i++)
            {
                context.MethodValues[i] = (int)context.MethodValues[i] + 1;
            }
            Console.WriteLine("执行前");
        }

        public override object After(AspectContext context)
        {
            Console.WriteLine("执行后");

            // 阻挡方式的执行效果
            context.MethodResult = (int)context.MethodResult + 664;

            if (context.IsMethod)
                return context.MethodResult;
            else if (context.IsProperty)
                return context.PropertyValue;
            return null;
        }
    }

    [Interceptor]
    public class Test
    {
        [Log]
        public virtual int Sum(int a, int b)
        {
            Console.WriteLine("运行中");
            return a + b;
        }
    }
            Test test = AopInterceptor.CreateProxyOfClass<Test>();

            Console.WriteLine(test.Sum(1, 1));

方式的参数支持 inrefout;支持泛型方式泛型属性;支持异步方式;

非侵入式署理

此种方式不需要改动被署理的类型,你也可以署理程序集中的类型。

    public class LogAttribute : ActionAttribute
    {
        public override void Before(AspectContext context)
        {
            Console.WriteLine("执行前");
        }

        public override object After(AspectContext context)
        {
            Console.WriteLine("执行后");
            if (context.IsMethod)
                return context.MethodResult;
            else if (context.IsProperty)
                return context.PropertyValue;
            return null;
        }
    }
    public class TestNo
    {
        public virtual string A { get; set; }
        public virtual void MyMethod()
        {
            Console.WriteLine("运行中");
        }
    }
            TestNo test3 = AopInterceptor.CreateProxyOfType<TestNo>(new ProxyTypeBuilder()
                .AddProxyMethod(typeof(LogAttribute), typeof(TestNo).GetMethod(nameof(TestNo.MyMethod)))
                .AddProxyMethod(typeof(LogAttribute), typeof(TestNo).GetProperty(nameof(TestNo.A)).GetSetMethod()));

通过 ProxyTypeBuilder 来构建署理类型。

署理方式或属性都是使用 AddProxyMethod,第一个参数是要使用的阻挡器,第二个参数是要阻挡的方式。

若是要阻挡属性,请离开设置属性的 getset 组织。

若是多个方式或属性使用同一个阻挡器,则可以这样:

            TestNo test3 = AopInterceptor.CreateProxyOfType<TestNo>(
                new ProxyTypeBuilder(new Type[] { typeof(LogAttribute) })
                .AddProxyMethod("LogAttribute", typeof(TestNo).GetMethod(nameof(TestNo.MyMethod)))
                .AddProxyMethod("LogAttribute", typeof(TestNo).GetProperty(nameof(TestNo.A)).GetSetMethod()));
            TestNo test3 = AopInterceptor.CreateProxyOfType<TestNo>(
                new ProxyTypeBuilder(new Type[] { typeof(LogAttribute) })
                .AddProxyMethod("LogAttribute", typeof(TestNo).GetMethod(nameof(TestNo.MyMethod)))
                .AddProxyMethod(typeof(LogAttribute2), typeof(TestNo).GetProperty(nameof(TestNo.A)).GetSetMethod()));

在组织函数中通报已往所需要的阻挡器,然后在阻挡时使用。

原创文章,作者:admin,如若转载,请注明出处:https://www.2lxm.com/archives/17124.html