zoukankan      html  css  js  c++  java
  • C#使用Autofac实现控制反转IoC和面向切面编程AOP

    C#使用Autofac实现控制反转IoC和面向切面编程AOP

    Autofac是一个.net下非常优秀,性能非常好的IOC容器(.net下效率最高的容器),加上AOP简直是如虎添翼。Autofac的AOP是通过Castle(也是一个容器)项目的核心部分实现的,名为Autofac.Extras.DynamicProxy,顾名思义,其实现方式为动态代理。

    使用方式比较简单,先新建一个控制台项目,然后在Nuget上搜索Autofac.Aop并安装,如下顺序:

    或者通过命令安装:

    Install-Package Autofac.Aop

    安装成功之后会项目会增加几个个引用,如下图:

    1. 创建拦截器

    复制代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    //先在Nuget上搜索Autofac.Aop安装
    using Castle.DynamicProxy;
    
    namespace AutofacDEMO
    {
        /// <summary>
        /// 拦截器 需要实现 IInterceptor接口 Intercept方法
        /// </summary>
        public class LogInterceptor : IInterceptor
        {
            /// <summary>
            /// 拦截方法 打印被拦截的方法执行前的名称、参数和方法执行后的 返回结果
            /// </summary>
            /// <param name="invocation">包含被拦截方法的信息</param>
            public void Intercept(IInvocation invocation)
            {
                Console.WriteLine("方法执行前:拦截{0}类下的方法{1}的参数是{2}",
                    invocation.InvocationTarget.GetType(),
                    invocation.Method.Name, string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));
    
                //在被拦截的方法执行完毕后 继续执行
                invocation.Proceed();
    
                Console.WriteLine("方法执行完毕,返回结果:{0}", invocation.ReturnValue);
                Console.WriteLine();
            }
        }
    }

    复制代码

    2. 创建拦截容器

    var builder = new ContainerBuilder();

    3. 注册拦截器到Autofac容器

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

    复制代码

    // 命名注入
    builder.Register(c => new LogInterceptor()).Named<IInterceptor>("log-calls");
    
    //类型注入
    builder.Register(c => new LogInterceptor());    
    //或者
    builder.RegisterType<LogInterceptor>();       

    复制代码

    4. 启用拦截器

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

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

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

     注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法

    复制代码

    //启用类代理拦截
    //方式一:给类型上加特性Attribute
    builder.RegisterType<Student>().EnableClassInterceptors();
    //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
    builder.RegisterType<Teacher>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
    //启用接口代理拦截
    //方式一:给类型上加特性Attribute
    builder.RegisterType<Man>().As<IPerson>().EnableInterfaceInterceptors();         
    //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
    builder.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();          

    复制代码

    5. 指明要拦截的类型

    有两种方法:

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

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

    //动态注入拦截器
    builder.RegisterType<Student>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();

    6. 测试效果如下

    第一种:类代理拦截

    复制代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Autofac.Extras.DynamicProxy2;
    
    namespace AutofacDEMO
    {
        /// <summary>
        /// 继承接口,并实现方法,给类型加上特性Attribute
        /// </summary>
        [Intercept(typeof(LogInterceptor))]
        public class Student
        {
            public string Name;
    
            public Teacher Teacher;
    
            public Subject Subject;
                   
            /// <summary>
            /// 必须是虚方法
            /// </summary>
            public virtual void Say()
            {
                Console.WriteLine("你正在调用Say方法!学生姓名:" + Name);
            }
        }
    
        [Intercept(typeof(LogInterceptor))]
        public class Teacher
        {      
            /// <summary>
            /// 必须是虚方法
            /// </summary>
            public virtual void Show()
            {
                Console.WriteLine("I am Teacher's class !");
            }
        }
    
        public class Subject
        {      
            /// <summary>
            /// 必须是虚方法
            /// </summary>
            public virtual void Show()
            {
                Console.WriteLine("I am Subject's class !" );
            }
        }
    }

    复制代码

    复制代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Autofac;
    using Autofac.Extras.DynamicProxy2;
    
    namespace AutofacDEMO
    {
        class Program
        {
            static void Main(string[] args)
            {
                //启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()
                //EnableInterfaceInterceptors方法会动态创建一个接口代理
                //EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法
                //注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法
                #region 启用类代理拦截
                //创建拦截容器
                var builder = new ContainerBuilder();
                //注册拦截器到容器
                builder.RegisterType<LogInterceptor>();        
                //方式一:给类型上加特性Attribute
                builder.RegisterType<Student>().EnableClassInterceptors();
                builder.RegisterType<Teacher>().EnableClassInterceptors();
                //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
                //builder.RegisterType<Teacher>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
                //builder.RegisterType<Student>().InterceptedBy(typeof(LogInterceptor)).EnableClassInterceptors();
                //属性注入
                builder.Register(c => new Student { Teacher = c.Resolve<Teacher>(), Subject = new Subject(), Name = "张三" });        
                using (var container = builder.Build())
                {
                    //从容器获取对象
                    var Student = container.Resolve<Student>();
                    Student.Say();
                    Student.Subject.Show();
                    Student.Teacher.Show();              
                }
                Console.ReadLine();
                #endregion      
            }
        }
    }

    复制代码

    第二种:接口代理拦截

    复制代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace AutofacDEMO
    {
        /// <summary>
        /// 定义一个接口
        /// </summary>
        public interface IPerson
        {
            void Say(string Name);
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Autofac.Extras.DynamicProxy2;
    
    namespace AutofacDEMO
    {
        /// <summary>
        /// 继承接口,并实现方法,给类型加上特性Attribute
        /// </summary>
        [Intercept(typeof(LogInterceptor))]
        public class Man: IPerson
        {
            public string Age;   
    
            public void Say(string Name)
            {
                Console.WriteLine("男人调用Say方法!姓名:" + Name + ",年龄:" + Age);
            }
        }
    
        /// <summary>
        /// 继承接口,并实现方法,给类型加上特性Attribute
        /// </summary>
        [Intercept(typeof(LogInterceptor))]
        public class Woman : IPerson
        {
            public void Say(string Name)
            {
                Console.WriteLine("女人调用Say方法!姓名:" + Name);
            }
        }
    
        /// <summary>
        /// 管理类
        /// </summary>
        public class PersonManager
        {
            IPerson _Person;
    
            /// <summary>
            /// 根据传入的类型动态创建对象
            /// </summary>
            /// <param name="ds"></param>
            public PersonManager(IPerson Person)
            {
                _Person = Person;
            }
    
            public void Say(string Name)
            {
                _Person.Say(Name);
            }
        }
    }
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Autofac;
    using Autofac.Extras.DynamicProxy2;
    
    namespace AutofacDEMO
    {
        class Program
        {
            static void Main(string[] args)
            {
                //启用拦截器主要有两个方法:EnableInterfaceInterceptors(),EnableClassInterceptors()
                //EnableInterfaceInterceptors方法会动态创建一个接口代理
                //EnableClassInterceptors方法会创建一个目标类的子类代理类,这里需要注意的是只会拦截虚方法,重写方法
                //注意:需要引用Autofac.Extras.DynamicProxy2才能使用上面两个方法      
                #region 启用接口代理拦截(推荐用这种方式)
                //创建拦截容器
                var builder2 = new ContainerBuilder();
                //注册拦截器到容器
                builder2.RegisterType<LogInterceptor>();
                //构造函数注入(只要调用者传入实现该接口的对象,就实现了对象创建,下面两种方式)
                builder2.RegisterType<PersonManager>();
                //方式一:给类型上加特性Attribute
                //属性注入
                builder2.Register<Man>(c => new Man { Age = "20" }).As<IPerson>().EnableInterfaceInterceptors();
                //builder2.RegisterType<Man>().As<IPerson>().EnableInterfaceInterceptors();
                builder2.RegisterType<Woman>().Named<IPerson>("Woman").EnableInterfaceInterceptors();
                //方式二:在注册类型到容器的时候动态注入拦截器(去掉类型上的特性Attribute)
                //builder2.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();
                //builder2.RegisterType<Woman>().Named<IPerson>("Woman").InterceptedBy(typeof(LogInterceptor)).EnableInterfaceInterceptors();    
                using (var container = builder2.Build())
                {
                    //从容器获取对象
                    var Manager = container.Resolve<PersonManager>();
                    Manager.Say("管理员");
                    var Person = container.Resolve<IPerson>();
                    Person.Say("张三");
                    var Woman = container.ResolveNamed<IPerson>("Woman");
                    Woman.Say("王萌");
                }
                Console.ReadLine();
                #endregion            
            }
        }
    }
    

    分类: .NET AOP

  • 相关阅读:
    parted分区
    gitlab的还原
    hadoop2.7.3+spark2.0.1+scala2.11.8集群部署
    Daily record-September
    三次握手和四次挥手【转】
    “梅西式”程序员 【转】
    C++解析十-数据封装
    客户端、服务器代码实例
    网络整理
    C++解析九-数据抽象
  • 原文地址:https://www.cnblogs.com/grj001/p/12223162.html
Copyright © 2011-2022 走看看