欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# Autofac学习笔记

程序员文章站 2022-04-15 21:22:26
一、为什么使用Autofac? Autofac是.NET领域最为流行的IoC框架之一,传说是速度最快的一个。 1.1、性能 有人专门做了测试: 1.2、优点 1)与C#语言联系很紧密。C#里的很多编程方式都可以为Autofac使用,例如可以使用Lambda表达式注册组件。 2)较低的学习曲线。学习它 ......

    一、为什么使用autofac?

    autofac是.net领域最为流行的ioc框架之一,传说是速度最快的一个。

    1.1、性能

    有人专门做了测试:

C# Autofac学习笔记C# Autofac学习笔记

    1.2、优点

    1)与c#语言联系很紧密。c#里的很多编程方式都可以为autofac使用,例如可以使用lambda表达式注册组件。

    2)较低的学习曲线。学习它非常的简单,只要你理解了ioc和di的概念以及在何时需要使用它们。

    3)支持json/xml配置。

    4)自动装配。

    5)与asp.net mvc集成。

    6)微软的orchad开源程序使用的就是autofac,可以看出它的方便和强大。

    1.3、资源

    官方网站:

    github网址:https://github.com/autofac/autofac

    学习资料:autofac中文文档

    二、数据准备

    2.1、新建项目

C# Autofac学习笔记

    iservice下的接口类:

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;

namespace linkto.test.autofac.iservice
{
    /// <summary>
    /// 动物吠声接口类
    /// </summary>
    public interface ianimalbark
    {
        /// <summary>
        /// 吠叫
        /// </summary>
        void bark();
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;

namespace linkto.test.autofac.iservice
{
    /// <summary>
    /// 动物睡眠接口类
    /// </summary>
    public interface ianimalsleep
    {
        /// <summary>
        /// 睡眠
        /// </summary>
        void sleep();
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;

namespace linkto.test.autofac.iservice
{
    /// <summary>
    /// 学校接口类
    /// </summary>
    public interface ischool
    {
        /// <summary>
        /// 放学
        /// </summary>
        void leaveschool();
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;

namespace linkto.test.autofac.iservice
{
    /// <summary>
    /// 学生接口类
    /// </summary>
    public interface istudent
    {
        /// <summary>
        /// 增加学生
        /// </summary>
        /// <param name="studentid">学生id</param>
        /// <param name="studentname">学生姓名</param>
        void add(string studentid, string studentname);
    }
}

    service下的接口实现类:

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using linkto.test.autofac.iservice;

namespace linkto.test.autofac.service
{
    /// <summary>
    /// 猫类
    /// </summary>
    public class cat : ianimalsleep
    {
        /// <summary>
        /// 睡眠
        /// </summary>
        public void sleep()
        {
            console.writeline("小猫咪睡着了zz");
        }
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using linkto.test.autofac.iservice;

namespace linkto.test.autofac.service
{
    /// <summary>
    /// 狗类
    /// </summary>
    public class dog : ianimalbark, ianimalsleep
    {
        /// <summary>
        /// 吠叫
        /// </summary>
        public void bark()
        {
            console.writeline("汪汪汪");
        }

        /// <summary>
        /// 睡眠
        /// </summary>
        public void sleep()
        {
            console.writeline("小狗狗睡着了zz");
        }
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using linkto.test.autofac.iservice;

namespace linkto.test.autofac.service
{
    /// <summary>
    /// 学校类
    /// </summary>
    public class school : ischool
    {
        /// <summary>
        /// ianimalbark属性
        /// </summary>
        public ianimalbark animalbark { get; set; }

        /// <summary>
        /// 放学
        /// </summary>
        public void leaveschool()
        {
            animalbark.bark();
            console.writeline("你家的熊孩子放学了⊙o⊙");
        }
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using linkto.test.autofac.iservice;

namespace linkto.test.autofac.service
{
    /// <summary>
    /// 学生类
    /// </summary>
    public class student : istudent
    {
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public student()
        { }

        /// <summary>
        /// 有参构造函数
        /// </summary>
        /// <param name="studentid">学生id</param>
        /// <param name="studentname">学生姓名</param>
        public student(string studentid, string studentname)
        {
            add(studentid, studentname);
        }

        /// <summary>
        /// 增加学生
        /// </summary>
        /// <param name="studentid">学生id</param>
        /// <param name="studentname">学生姓名</param>
        public void add(string studentid, string studentname)
        {
            console.writeline($"新增的学生是:{studentname}");
        }
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading;
using system.threading.tasks;
using linkto.test.autofac.iservice;

namespace linkto.test.autofac.service
{
    /// <summary>
    /// 动物摇尾巴
    /// </summary>
    public class animalwagging
    {
        /// <summary>
        /// ianimalbark属性
        /// </summary>
        ianimalbark animalbark;

        /// <summary>
        /// 有参构造函数
        /// </summary>
        /// <param name="bark">ianimalbark变量</param>
        public animalwagging(ianimalbark bark)
        {
            animalbark = bark;
        }

        /// <summary>
        /// 摇尾巴
        /// </summary>
        public virtual void wagging()
        {
            animalbark.bark();
            console.writeline("摇尾巴");
        }

        /// <summary>
        /// 计数
        /// </summary>
        /// <returns></returns>
        public static int count()
        {
            return 6;
        }

        /// <summary>
        /// 任务
        /// </summary>
        /// <param name="name">动物名称</param>
        /// <returns></returns>
        public virtual async task<string> waggingasync(string name)
        {
            var result = await task.run(() => count());
            return $"{name}摇了{result}下尾巴";
        }
    }
}

    2.2、autofac安装

    client项目右键->管理 nuget 程序包->autofac。

C# Autofac学习笔记

    三、ioc-注册

    3.1、类型注册

    a)类型注册:使用registertype进行注册。

            //注册autofac组件
            containerbuilder builder = new containerbuilder();
            //注册实现类student,当我们请求istudent接口的时候,返回的是类student的对象。
            builder.registertype<student>().as<istudent>();
            //上面这句也可改成下面这句,这样请求student实现了的任何接口的时候,都会返回student对象。
            //builder.registertype<student>().asimplementedinterfaces();
            icontainer container = builder.build();
            //请求istudent接口
            istudent student = container.resolve<istudent>();
            student.add("1001", "hello");

    b)类型注册(别名):假如一个接口有多个实现类,可以在注册时起别名。

            containerbuilder builder = new containerbuilder();
            builder.registertype<dog>().named<ianimalsleep>("dog");
            builder.registertype<cat>().named<ianimalsleep>("cat");
            icontainer container = builder.build();

            var dog = container.resolvenamed<ianimalsleep>("dog");
            dog.sleep();
            var cat = container.resolvenamed<ianimalsleep>("cat");
            cat.sleep();

    c)类型注册(枚举):假如一个接口有多个实现类,也可以使用枚举的方式注册。

        public enum animaltype
        {
            dog,
            cat
        }
            containerbuilder builder = new containerbuilder();
            builder.registertype<dog>().keyed<ianimalsleep>(animaltype.dog);
            builder.registertype<cat>().keyed<ianimalsleep>(animaltype.cat);
            icontainer container = builder.build();

            var dog = container.resolvekeyed<ianimalsleep>(animaltype.dog);
            dog.sleep();
            var cat = container.resolvekeyed<ianimalsleep>(animaltype.cat);
            cat.sleep();

    3.2、实例注册

            containerbuilder builder = new containerbuilder();
            builder.registerinstance<istudent>(new student());
            icontainer container = builder.build();

            istudent student = container.resolve<istudent>();
            student.add("1001", "hello");

    3.3、lambda注册

    a)lambda注册

            containerbuilder builder = new containerbuilder();
            builder.register(c => new student()).as<istudent>();
            icontainer container = builder.build();

            istudent student = container.resolve<istudent>();
            student.add("1001", "hello");

    b)lambda注册(namedparameter)

            containerbuilder builder = new containerbuilder();
            builder.register<ianimalsleep>((c, p) =>
                {
                    var type = p.named<string>("type");
                    if (type == "dog")
                    {
                        return new dog();
                    }
                    else
                    {
                        return new cat();
                    }
                }).as<ianimalsleep>();
            icontainer container = builder.build();

            var dog = container.resolve<ianimalsleep>(new namedparameter("type", "dog"));
            dog.sleep();

    3.4、程序集注册

    如果有很多接口及实现类,假如觉得这种一一注册很麻烦的话,可以一次性全部注册,当然也可以加筛选条件。

            containerbuilder builder = new containerbuilder();
            assembly assembly = assembly.load("linkto.test.autofac.service");   //实现类所在的程序集名称
            builder.registerassemblytypes(assembly).asimplementedinterfaces();  //常用
            //builder.registerassemblytypes(assembly).where(t=>t.name.startswith("s")).asimplementedinterfaces();  //带筛选
            //builder.registerassemblytypes(assembly).except<school>().asimplementedinterfaces();  //带筛选
            icontainer container = builder.build();

            //单实现类的用法
            istudent student = container.resolve<istudent>();
            student.add("1001", "hello");

            //多实现类的用法
            ienumerable<ianimalsleep> animals = container.resolve<ienumerable<ianimalsleep>>();
            foreach (var item in animals)
            {
                item.sleep();
            }

    3.5、泛型注册

            containerbuilder builder = new containerbuilder();
            builder.registergeneric(typeof(list<>)).as(typeof(ilist<>));
            icontainer container = builder.build();

            ilist<string> list = container.resolve<ilist<string>>();

    3.6、默认注册

            containerbuilder builder = new containerbuilder();
            //对于同一个接口,后面注册的实现会覆盖之前的实现。
            //如果不想覆盖的话,可以用preserveexistingdefaults,这样会保留原来注册的实现。
            builder.registertype<dog>().as<ianimalsleep>();
            builder.registertype<cat>().as<ianimalsleep>().preserveexistingdefaults();  //指定为非默认值
            icontainer container = builder.build();

            var dog = container.resolve<ianimalsleep>();
            dog.sleep();

    四、ioc-注入

    4.1、构造函数注入

            containerbuilder builder = new containerbuilder();
            builder.registertype<animalwagging>();
            builder.registertype<dog>().as<ianimalbark>();
            icontainer container = builder.build();

            animalwagging animal = container.resolve<animalwagging>();
            animal.wagging();

    4.2、属性注入

            containerbuilder builder = new containerbuilder();
            assembly assembly = assembly.load("linkto.test.autofac.service");                           //实现类所在的程序集名称
            builder.registerassemblytypes(assembly).asimplementedinterfaces().propertiesautowired();    //常用
            icontainer container = builder.build();

            ischool school = container.resolve<ischool>();
            school.leaveschool();

    五、ioc-事件

    autofac在组件生命周期的不同阶段,共对应了5个事件,执行顺序如下所示:

    1.onregistered->2.onpreparing->3.onactivating->4.onactivated->5.onrelease

            containerbuilder builder = new containerbuilder();
            builder.registertype<student>().as<istudent>()
                .onregistered(e => console.writeline("onregistered:在注册的时候调用"))
                .onpreparing(e => console.writeline("onpreparing:在准备创建的时候调用"))
                .onactivating(e => console.writeline("onactivating:在创建之前调用"))
                //.onactivating(e => e.replaceinstance(new student("1000", "test")))
                .onactivated(e => console.writeline("onactivated:在创建之后调用"))
                .onrelease(e => console.writeline("onrelease:在释放占用的资源之前调用"));
            using (icontainer container = builder.build())
            {
                istudent student = container.resolve<istudent>();
                student.add("1001", "hello");
            }

    六、ioc-生命周期

    6.1、per dependency

    per dependency:为默认的生命周期,也被称为"transient"或"factory",其实就是每次请求都创建一个新的对象。

            containerbuilder builder = new containerbuilder();
            assembly assembly = assembly.load("linkto.test.autofac.service");                                                   //实现类所在的程序集名称
            builder.registerassemblytypes(assembly).asimplementedinterfaces().propertiesautowired().instanceperdependency();    //常用
            icontainer container = builder.build();

            ischool school1 = container.resolve<ischool>();
            ischool school2 = container.resolve<ischool>();
            console.writeline(school1.equals(school2));

    6.2、single instance

    single instance:就是每次都用同一个对象。

            containerbuilder builder = new containerbuilder();
            assembly assembly = assembly.load("linkto.test.autofac.service");                                           //实现类所在的程序集名称
            builder.registerassemblytypes(assembly).asimplementedinterfaces().propertiesautowired().singleinstance();   //常用
            icontainer container = builder.build();

            ischool school1 = container.resolve<ischool>();
            ischool school2 = container.resolve<ischool>();
            console.writeline(referenceequals(school1, school2));

    6.3、per lifetime scope

    per lifetime scope:同一个lifetime生成的对象是同一个实例。

            containerbuilder builder = new containerbuilder();
            builder.registertype<school>().as<ischool>().instanceperlifetimescope();
            icontainer container = builder.build();
            ischool school1 = container.resolve<ischool>();
            ischool school2 = container.resolve<ischool>();
            console.writeline(school1.equals(school2));
            using (ilifetimescope lifetime = container.beginlifetimescope())
            {
                ischool school3 = lifetime.resolve<ischool>();
                ischool school4 = lifetime.resolve<ischool>();
                console.writeline(school3.equals(school4));
                console.writeline(school2.equals(school3));
            }

    七、ioc-通过配置文件使用autofac

    7.1、组件安装

    client项目右键->管理 nuget 程序包->autofac.configuration及microsoft.extensions.configuration.xml。

C# Autofac学习笔记

C# Autofac学习笔记

    7.2、配置文件

    新建一个autofacconfigioc.xml文件,在其属性的复制到输出目录项下选择始终复制。

<?xml version="1.0" encoding="utf-8" ?>
<autofac defaultassembly="linkto.test.autofac.iservice">
  <!--无注入-->
  <components name="1001">
    <type>linkto.test.autofac.service.student, linkto.test.autofac.service</type>
    <services name="0" type="linkto.test.autofac.iservice.istudent" />
    <injectproperties>true</injectproperties>
  </components>
  <components name="1002">
    <type>linkto.test.autofac.service.dog, linkto.test.autofac.service</type>
    <services name="0" type="linkto.test.autofac.iservice.ianimalbark" />
    <injectproperties>true</injectproperties>
  </components>
  <!--构造函数注入-->
  <components name="2001">
    <type>linkto.test.autofac.service.animalwagging, linkto.test.autofac.service</type>
    <services name="0" type="linkto.test.autofac.service.animalwagging, linkto.test.autofac.service" />
    <injectproperties>true</injectproperties>
  </components>
  <!--属性注入-->
  <components name="3001">
    <type>linkto.test.autofac.service.school, linkto.test.autofac.service</type>
    <services name="0" type="linkto.test.autofac.iservice.ischool" />
    <injectproperties>true</injectproperties>
  </components>
</autofac>

    7.3、测试代码

            //加载配置
            containerbuilder builder = new containerbuilder();
            var config = new configurationbuilder();
            config.addxmlfile("autofacconfigioc.xml");
            var module = new configurationmodule(config.build());
            builder.registermodule(module);
            icontainer container = builder.build();
            //无注入测试
            istudent student = container.resolve<istudent>();
            student.add("1002", "world");
            //构造函数注入测试
            animalwagging animal = container.resolve<animalwagging>();
            animal.wagging();
            //属性注入测试
            ischool school = container.resolve<ischool>();
            school.leaveschool();

    八、aop 

    8.1、组件安装

    client项目右键->管理 nuget 程序包->autofac.extras.dynamicproxy。

C# Autofac学习笔记

    8.2、拉截器

using system;
using system.collections.generic;
using system.io;
using system.linq;
using system.reflection;
using system.text;
using system.threading.tasks;
using castle.dynamicproxy;

namespace linkto.test.autofac.client
{
    /// <summary>
    /// 拦截器:需实现iinterceptor接口。
    /// </summary>
    public class calllogger : iinterceptor
    {
        private readonly textwriter _output;

        public calllogger(textwriter output)
        {
            _output = output;
        }

        /// <summary>
        /// 拦截方法:打印被拦截的方法--执行前的名称、参数以及执行后的返回结果。
        /// </summary>
        /// <param name="invocation">被拦截方法的信息</param>
        public void intercept(iinvocation invocation)
        {
            //空白行
            _output.writeline();

            //在下一个拦截器或目标方法处理之前的处理
            _output.writeline($"调用方法:{invocation.method.name}");

            if (invocation.arguments.length > 0)
            {
                _output.writeline($"参数:{string.join(", ", invocation.arguments.select(a => (a ?? "").tostring()).toarray())}");
            }

            //调用下一个拦截器(若存在),直到最终的目标方法(target method)。
            invocation.proceed();

            //获取被代理方法的返回类型
            var returntype = invocation.method.returntype;

            //异步方法
            if (isasyncmethod(invocation.method))
            {
                //task:返回值是固定类型
                if (returntype != null && returntype == typeof(task))
                {
                    //定义一个异步方法来等待目标方法返回的task
                    async task continuation() => await (task)invocation.returnvalue;
                    //continuation()中并没有使用await,所以continuation()就如同步方法一样是阻塞的。
                    invocation.returnvalue = continuation();
                }
                //task<t>:返回值是泛型类型
                else
                {
                    //获取被代理方法的返回类型
                    var returntypet = invocation.method.reflectedtype;
                    if (returntypet != null)
                    {
                        //获取泛型参数集合,集合中的第一个元素等价于typeof(class)。
                        var resulttype = invocation.method.returntype.getgenericarguments()[0];
                        //利用反射获得等待返回值的异步方法
                        methodinfo methodinfo = typeof(calllogger).getmethod("handleasync", bindingflags.public | bindingflags.instance);
                        //调用methodinfo类的makegenericmethod()方法,用获得的类型t(<resulttype>)来重新构造handleasync()方法。
                        var mi = methodinfo.makegenericmethod(resulttype);
                        //invoke:使用指定参数调用由当前实例表示的方法或构造函数。
                        invocation.returnvalue = mi.invoke(this, new[] { invocation.returnvalue });
                    }
                }

                var type = invocation.method.returntype;
                var resultproperty = type.getproperty("result");

                if (resultproperty != null)
                    _output.writeline($"方法结果:{resultproperty.getvalue(invocation.returnvalue)}");
            }
            //同步方法
            else
            {
                if (returntype != null && returntype != typeof(void))
                    _output.writeline($"方法结果:{invocation.returnvalue}");
            }
        }

        /// <summary>
        /// 判断是否异步方法
        /// </summary>
        public static bool isasyncmethod(methodinfo method)
        {
            return 
                (
                    method.returntype == typeof(task) || 
                    (method.returntype.isgenerictype && method.returntype.getgenerictypedefinition() == typeof(task<>))
                );
        }

        /// <summary>
        /// 构造等待返回值的异步方法
        /// </summary>
        /// <typeparam name="t"></typeparam>
        /// <param name="task"></param>
        /// <returns></returns>
        public async task<t> handleasync<t>(task<t> task)
        {
            var t = await task;
            return t;
        }
    }
}
using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading.tasks;
using castle.dynamicproxy;

namespace linkto.test.autofac.client
{
    public class calltester: iinterceptor
    {
        public void intercept(iinvocation invocation)
        {
            console.writeline("啥也不干");
            invocation.proceed();
            console.writeline("也不干啥");
        }
    }
}

    8.3、测试代码

    注意:对于以类方式的注入,autofac interceptor要求类的方法必须为virtual方法。如animalwagging类的wagging()、waggingasync(string name)都加了virtual修饰符。

            containerbuilder builder = new containerbuilder();

            //注册拦截器
            builder.register(c => new calllogger(console.out));
            builder.register(c => new calltester());

            //动态注入拦截器

            //这里定义了两个拦截器,注意它们的顺序。
            builder.registertype<student>().as<istudent>().interceptedby(typeof(calllogger), typeof(calltester)).enableinterfaceinterceptors();

            //这里定义了一个拦截器
            builder.registertype<animalwagging>().interceptedby(typeof(calllogger)).enableclassinterceptors();
            builder.registertype<dog>().as<ianimalbark>();

            icontainer container = builder.build();
            istudent student = container.resolve<istudent>();
            student.add("1003", "kobe");

            animalwagging animal = container.resolve<animalwagging>();
            animal.wagging();

            task<string> task = animal.waggingasync("哈士奇");
            console.writeline($"{task.result}");

 

    ioc参考自:

    https://www.xin3721.com/articlecsharp/c14013.html

    https://www.cnblogs.com/googlegetz/p/10218721.html

    

    

 

    aop参考自: