当前位置: 移动技术网 > IT编程>开发语言>c# > C# Autofac学习笔记

C# Autofac学习笔记

2020年05月09日  | 移动技术网IT编程  | 我要评论

    一、为什么使用autofac?

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

    1.1、性能

    有人专门做了测试:

    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、新建项目

    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。

    三、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。

    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。

    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参考自:

    

    

    

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网