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();
        }
    }
}
View Code

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 !" );
        }
    }
}
View Code
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      
        }
    }
}
View Code

第二種:接口代理攔截

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);
    }
}
View Code
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);
        }
    }
}
View Code
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            
        }
    }
}
View Code

Autofac三種生命周期:InstancePerLifetimeScope、SingleInstance、InstancePerDependency

InstancePerLifetimeScope:同一個Lifetime生成的對象是同一個實例

SingleInstance:單例模式,每次調用,都會使用同一個實例化的對象;每次都用同一個對象;

InstancePerDependency:默認模式,每次調用,都會重新實例化對象;每次請求都創建一個新的對象

//方式二:在注冊類型到容器的時候動態注入攔截器(去掉類型上的特性Attribute)
builder.RegisterType<Man>().As<IPerson>().InterceptedBy(typeof(LogInterceptor)).InstancePerLifetimeScope().EnableInterfaceInterceptors();

看下面運行結果圖

1、InstancePerLifetimeScope 

2、SingleInstance

3、InstancePerDependency

AsImplementedInterfaces()  是以接口方式進行注入,注入這些類的所有的公共接口作為服務(除了釋放資源)

builder.RegisterAssemblyTypes  注冊程序集中符合條件的類型

 Assembly assembly = Assembly.Load(assemblyName);
 //Assembly assembly = this.GetType().GetTypeInfo().Assembly;
 builder.RegisterAssemblyTypes(assembly).Where(type => !type.IsInterface && !type.IsSealed && !type.IsAbstract 
                       && type.Name.EndsWith("BLL", StringComparison.OrdinalIgnoreCase))
                       .AsImplementedInterfaces()
                       .InstancePerLifetimeScope()
                       .EnableInterfaceInterceptors()
                       .InterceptedBy(typeof(LogInterceptor));

每個RegisterAssemblyTypes()調用將僅應用一組規則 - 如果要注冊多個不同組的組件,則需要多次調用RegisterAssemblyTypes()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM