隐藏

.NET 通过 Autofac 和 DynamicProxy 实现AOP

发布:2022/1/4 16:00:47作者:管理员 来源:本站 浏览次数:922

什么是AOP?引用百度百科:AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。实现AOP主要由两种方式,一种是编译时静态植入,优点是效率高,缺点是缺乏灵活性,.net下postsharp为代表者(这个是收费的)。另一种方式是动态代理,优缺点与前者相反,动态为目标类型创建代理,通过代理调用实现拦截。AOP能做什么,常见的用例是事务处理、日志记录等等。下面就讲讲Autofac怎么实现AOP,Autofac是一个.net下非常优秀,性能非常好的IOC容器(.net下效率最高的容器),加上AOP简直是如虎添翼。Autofac的AOP是通过Castle(也是一个容器)项目的核心部分实现的,名为Autofac.Extras.DynamicProxy,顾名思义,其实现方式为动态代理。

使用前的准备:

通过Nuget安装程序包 :Autofac、Autofac.Extras.DynamicProxy,安装成功之后会增加三个引用

下面正式开始了!

 

第一步:创建拦截器

下面是一个简单的拦截器示例,该拦截器的功能是显示被拦截的方法名称、参数列表和返回结果

using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestWinService
{
    /// <summary>
    /// 拦截器 需要实现 IInterceptor接口 Intercept方法
    /// </summary>
    public class CallLogger : IInterceptor
    {
        TextWriter _output;

        public CallLogger(TextWriter output)
        {
            _output = output;
        }

        /// <summary>
        /// 拦截方法 打印被拦截的方法执行前的名称、参数和方法执行后的 返回结果
        /// </summary>
        /// <param name="invocation">包含被拦截方法的信息</param>
        public void Intercept(IInvocation invocation)
        {

            _output.WriteLine("你正在调用方法 \"{0}\"  参数是 {1}... ",
              invocation.Method.Name,
              string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

            //在被拦截的方法执行完毕后 继续执行
            invocation.Proceed();

            _output.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue);
        }
    }
}

第二步:注册拦截器到Autofac容器

拦截器必须注册到Aufofac容器中,可以通过拦截器类型或者命名注入,这两种方式会让使用拦截器的方法有所不同(后面会讲到)。

// 命名注入
            builder.Register(c => new CallLogger(Console.Out))
                   .Named<IInterceptor>("log-calls");

            // 类型注入
            builder.Register(c => new CallLogger(Console.Out));

第三步:启用拦截器

启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()。

EnableInterfaceInterceptors方法会动态创建一个接口代理

EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法

启用拦截器示例代码:


//启用类代理拦截 builder.RegisterType<Circle>().EnableClassInterceptors();  //启用接口代理拦截 builder.RegisterType<Circle>().EnableInterfaceInterceptors();

第四步:指明要拦截的类型

有两种方法:

第一种:给类型加上特性Attribute

第二种:在注册类型到容器的时候动态注入拦截器

//动态注入拦截器CallLogger
builder.RegisterType<Circle>().InterceptedBy(typeof(CallLogger)).EnableClassInterceptors();
第五步:测试效果了

1.类代理拦截

Circle类代码:

2.接口代理拦截

using Autofac;
using Autofac.Extras.DynamicProxy;
using System;

namespace TestWinService
{
    class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            //动态注入拦截器CallLogger 启用接口代理拦截
            builder.RegisterType<Circle>().As<IShape>().InterceptedBy(typeof(CallLogger)).EnableInterfaceInterceptors();
            builder.Register(c=>new CallLogger(Console.Out));
            //创建容器
            var container = builder.Build();
            //从容器获取类型
            var circle = container.Resolve<IShape>();
            //调用求面积方法
            circle.Area();
            
            Console.WriteLine("Hello World!");
            Console.ReadKey();
        }
    }
}

IShape接口代码:

public interface IShape
    {
        /// <summary>
        /// 形状的面积
        /// </summary>
        void Area();

    }

public class Circle:IShape
    {
        //重写父类抽象方法
        public void Area()
        {
            Console.WriteLine("你正在调用圆求面积的方法");
        }
    }