依赖注入之Autofac使用总结

依赖倒置?控制反转(IOC)? 依赖注入(DI)?

你是否还在被这些名词所困扰,是否看了大量理论文章后还是一知半解了?

今天我想结合实际项目,和正在迷惑中的新手朋友一起来学习和总结依赖注入Autofac的使用和理解。

依赖注入粗暴理解

依赖: 

public class A
{   
public void A(B b){
// do something} }

这样的代码,估计没有程序猿不曾使用。

A类实例化的时候需要一个B的对象作为构造函数的参数,那么A就依赖B,这就叫依赖。

当然,不用构造函数的方式,在A类内部去new一个B,其实也是一样存在A依赖B。

注入:

看到“注入”一词,第一想到的是不是注射器?哈哈,还生活在童年阴影中。 结合一下“打针”这个场景来简单理解下依赖注入。
医生使用注射器(Autofac),将药物(依赖=类对象),注入到血管(其他类中)。

Autofac的基本使用

搭建项目

创建一个MVC项目,通过Nuget直接添加Autofac。

 注入类本身.AsSelf()

    public class TestController : Controller{      

private readonly InjectionTestService _testService;

public TestController(InjectionTestService testService){_testService = testService;}

public ActionResult Index(){ViewBag.TestValue = _testService.Test();
return View();}}


    public class InjectionTestService : IService{        public string Test(){            return "Success";}}

在Global.asax中加入依赖注入的注册代码

            // 创建一个容器var builder = new ContainerBuilder();            // 注册所有的Controllerbuilder.RegisterControllers(Assembly.GetExecutingAssembly());            // RegisterType方式:builder.RegisterType<InjectionTestService>().AsSelf().InstancePerDependency();            // Register方式:builder.Register(c => new InjectionTestService()).AsSelf().InstancePerDependency();            // 自动注入的方式,不需要知道具体类的名称/* BuildManager.GetReferencedAssemblies()* 程序集的集合,包含 Web.config 文件的 assemblies 元素中指定的程序集、* 从 App_Code 目录中的自定义代码生成的程序集以及其他顶级文件夹中的程序集。             */// 获取包含继承了IService接口类的程序集var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().Where(assembly =>assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) !=                        null);            // RegisterAssemblyTypes 注册程序集var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();  
if (enumerable.Any()){builder.RegisterAssemblyTypes(enumerable).Where(type => type.GetInterfaces().Contains(typeof(IService))).AsSelf().InstancePerDependency();} // 把容器装入到微软默认的依赖注入容器中var container = builder.Build();DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

为接口注入具体类.AsImplementedInterfaces()

    public class TestController : Controller{     
private readonly IService _testService;
public TestController(IService testService){_testService = testService;} public ActionResult Index(){ViewBag.TestValue = _testService.Test();
return View();}}
            // Register 方式指定具体类builder.Register(c => new InjectionTestService()).As<IService>().InstancePerDependency();            // RegisterType 方式指定具体类builder.RegisterType<InjectionTestService>().As<IService>().InstancePerDependency();            // 自动注册的方式            // 获取包含继承了IService接口类的程序集var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>().Where(assembly =>assembly.GetTypes().FirstOrDefault(type => type.GetInterfaces().Contains(typeof(IService))) !=                        null);            // RegisterAssemblyTypes 注册程序集var enumerable = assemblies as Assembly[] ?? assemblies.ToArray();     
if (enumerable.Any()){builder.RegisterAssemblyTypes(enumerable).Where(type => type.GetInterfaces().Contains(typeof(IService))).AsImplementedInterfaces().InstancePerDependency();}

 利用Named自动注入依赖类

需求场景说明:

有A、B、C三个短信平台提供发送短信业务;

分别有三个短信平台的实现类,AMessage,BMessage,CMessage;

客户端在不同时段选取不同平台发送短信。

常规简单处理方式

新建三个服务类,AMsgService,BMsgService,CMsgService。
在客户端通过 if else 的方式判断要选用哪个短信平台,然后new服务类对象,再调用Send方法发送短信。

缺点

如果有新的短信平台D加入的话,必须新建一个DSendMsgService,然后修改客户端if else 代码。

改造

抽象一个短信平台的接口
    public interface IMessage{      
decimal QueryBalance();
bool Send(string msg);
int TotalSend(DateTime? startDate, DateTime? endDate);}

 具体实现类

    [MessagePlatform(Enums.MPlatform.A平台)]  
public class ASendMessageService : IMessage{ public decimal QueryBalance(){ return 0;} public bool Send(string msg){ return true;} public int TotalSend(DateTime? startDate, DateTime? endDate){ return 100;}}

类有一个自定义属性标签MessagePlatform,这个是干嘛了? 是为了给这个类做一个标记,结合Named使用,实现自动注入。

    public class TestController : Controller{  
private Func<int, IMessage> _factory;
public TestController(Func<int, IMessage> factory){_factory = factory;}
public ActionResult Index(){
var retult = _factory((int)Enums.MPlatform.A平台).Send("去你的吧");
return View(retult);}}

构造函数参数居然是一个func的委托?

这个factory传入参数是一个int(定义好的短信平台枚举值),就可以拿到这个短信平台具体的实现类?

没错,autofac就是这么任性。

            builder.RegisterType<ASendMessageService>().Named<IMessage>((                        // 获取类自定义属性typeof(ASendMessageService).GetCustomAttributes(typeof(MessagePlatformAttribute), false).FirstOrDefault()                        as MessagePlatformAttribute).platform.ToString()).InstancePerRequest();builder.Register<Func<int, IMessage>>(c =>{                var ic = c.Resolve<IComponentContext>();                return name => ic.ResolveNamed<IMessage>(name.ToString());});

疑问:

上面只是给 ASendMessageService类实现了自动注入,那么BSendMessageService,CSendMessageService怎么办了,不可能都去复制一段注入的配置代码吧?

            typeof(IMessage).Assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IMessage))).ForEach(type =>{// 注册type});

如果你有些实现类不在IMessge这个程序集下,那就不能这么写了,要结合具体项目情况来调整代码。

总结

1.依赖注入的目的是为了解耦。

2.不依赖于具体类,而依赖抽象类或者接口,这叫依赖倒置。

3.控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。

4. 微软的DependencyResolver如何创建controller 【后续学习】

Autofac创建类的生命周期

1、InstancePerDependency

对每一个依赖或每一次调用创建一个新的唯一的实例。这也是默认的创建实例的方式。

官方文档解释:Configure the component so that every dependent component or call to Resolve() gets a new, unique instance (default.) 

2、InstancePerLifetimeScope

在一个生命周期域中,每一个依赖或调用创建一个单一的共享的实例,且每一个不同的生命周期域,实例是唯一的,不共享的。

官方文档解释:Configure the component so that every dependent component or call to Resolve() within a single ILifetimeScope gets the same, shared instance. Dependent components in different lifetime scopes will get different instances. 

3、InstancePerMatchingLifetimeScope

在一个做标识的生命周期域中,每一个依赖或调用创建一个单一的共享的实例。打了标识了的生命周期域中的子标识域中可以共享父级域中的实例。若在整个继承层次中没有找到打标识的生命周期域,则会抛出异常:DependencyResolutionException。

官方文档解释:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope tagged with any of the provided tags value gets the same, shared instance. Dependent components in lifetime scopes that are children of the tagged scope will share the parent's instance. If no appropriately tagged scope can be found in the hierarchy an DependencyResolutionException is thrown. 

4、InstancePerOwned

在一个生命周期域中所拥有的实例创建的生命周期中,每一个依赖组件或调用Resolve()方法创建一个单一的共享的实例,并且子生命周期域共享父生命周期域中的实例。若在继承层级中没有发现合适的拥有子实例的生命周期域,则抛出异常:DependencyResolutionException。

官方文档解释:Configure the component so that every dependent component or call to Resolve() within a ILifetimeScope created by an owned instance gets the same, shared instance. Dependent components in lifetime scopes that are children of the owned instance scope will share the parent's instance. If no appropriate owned instance scope can be found in the hierarchy an DependencyResolutionException is thrown. 

5、SingleInstance

每一次依赖组件或调用Resolve()方法都会得到一个相同的共享的实例。其实就是单例模式。

官方文档解释:Configure the component so that every dependent component or call to Resolve() gets the same, shared instance. 

6、InstancePerHttpRequest  (新版autofac建议使用InstancePerRequest)

在一次Http请求上下文中,共享一个组件实例。仅适用于asp.net mvc开发。
官方文档解释:Share one instance of the component within the context of a single HTTP request.

 

 参考文档:
https://stackoverflow.com/questions/2888621/autofacs-funct-to-resolve-named-service

http://blog.csdn.net/dhx20022889/article/details/9061483

相关文章:

  • 使用 Autofac 进行依赖注入

  • ASP.NET Core依赖注入解读&使用Autofac替代实现

  • ASP.NET Core 整合Autofac和Castle实现自动AOP拦截

原文地址:http://www.cnblogs.com/struggle999/p/6986903.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325165.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaFX官方教程(十二)之树动画示例

翻译自 树动画示例 本章提供有关树动画示例的详细信息。您将了解场景中的所有元素是如何创建和动画的。 图4-1显示了带树的场景。 图4-1树动画 项目和要素 树动画项目由几个文件组成。每个元素&#xff0c;如树叶&#xff0c;草叶等&#xff0c;都是在不同的类中创建的。在…

《走遍中国》珍藏版(一)

Console.WriteLine("上一本书已经看完&#xff0c;从今天开始看下一本"); System.out.println("《走遍中国》珍藏版"); System.out.println("这本书是关于地理的"); System.out.println("地理往往是和历史进行紧密联系的");北京、天津…

MySQL建表,DML,DDL,约束,外键策略

创建数据库表 CREATE TABLE student( sno int (6), sname VARCHAR(10), sex CHAR(1), age INT(2), enterdate date, classname VARCHAR(10), email VARCHAR(15) ); – 查看表的结构 desc student – 查看表的数据 SELECT * FROM student DML – 查询表的数据 SELECT * FRO…

ssl1197-质数和分解【dp练习】

Description   任何大于 1 的自然数 n&#xff0c;都可以写成若干个大于等于 2 &#xff0c;且小于等于 n 的质数之和表达式(包括只有一个数构成的和表达式的情况)&#xff0c;并且可能有不止一种质数和的形式。例如9 的质数和表达式就有四种本质不同的形式&#xff1a; 9 …

像素密度(衡量屏幕显示能力)

像素密度√[(长度像素数)^2(宽度像素数)^2]/屏幕尺寸 eg:

通过Roslyn构建自己的C#脚本(更新版)

之前写过文章介绍过如何通过Roslyn构建自己的C#脚本&#xff0c;但那篇文章是参考自Roslyn CTP版的&#xff0c;记得本来想等到Roslyn正式版出来重新更新一下文档的&#xff0c;不过记得后来Roslyn是跳票了的&#xff0c;Scripting API在正式版本中都一度被移除了&#xff0c;这…

JavaFX官方教程(十三)之应用效果

翻译自 Applying Effects 创建视觉效果包含以下主题&#xff1a; 混合效果 绽放效果 模糊效果 投影效果 内阴影效果 反射 照明效果 透视效果 创建一系列效果 介绍如何使用视觉效果来增强JavaFX应用程序的外观。 所有效果都位于javafx.scene.effect包中&#xff0c;…

《走遍中国》珍藏版(二)

Console.WriteLine("上一本书已经看完&#xff0c;从今天开始看下一本"); System.out.println("《走遍中国》珍藏版"); System.out.println("这本书是关于地理的"); System.out.println("地理往往是和历史进行紧密联系的");大门两侧傲…

单表查询

最简单的查询语句 select * from dept select * from emp; – 显示部分列 select empno,ename,sal ,comm,deptno from emp – 显示部分行 where select empno,ename,sal ,comm,deptno from emp where sal<2500 – 别名 select empno 编号,ename 姓名,sal 工资 ,comm 补助…

ssl1072-砝码称重【dp练习】

Description 设有1g、2g、3g、5g、10g、20g的砝码各若干枚&#xff08;其总重<1000&#xff09;&#xff0c; 要求&#xff1a; 输入方式&#xff1a;a1 a2 a3 a4 a5 a6 &#xff08;表示1g砝码有a1个&#xff0c;2g砝码有a2个&#xff0c;…&#xff0c;20g砝码有a6个&…

java中遍历树形菜单,你可能不知道还有这样的方法

版权声明&#xff1a;本文为CSDN博主「穆雄雄」的原创文章&#xff0c;遵循CC 4.0 BY-SA版权协议&#xff0c;转载请附上原文出处链接及本声明。原文链接&#xff1a;https://blog.csdn.net/qq_34137397/article/details/72654955穆雄雄开发工具&#xff1a;MyEclipse 10.5后台…

Docker-Compose 一键部署Ningx+.Net Core+Redis集群

在看该文章前&#xff0c;你需要对Docker有所了解。 1、创建WebApp应用程序 我使用的是.Net Core 1.0.1版本&#xff0c;创建一个MVC应用程序&#xff0c;并添加对Redis的引用。因为这些很基础&#xff0c;也很简单&#xff0c;这里就不详细说明了&#xff0c;特别提一下有关多…

JavaFX官方教程(十四)之转换,动画和视觉效果教程的源代码

翻译自 转换&#xff0c;动画和视觉效果教程的源代码 下表列出了本文档中的演示应用程序及其关联的源代码文件。 教程源代码NetBeans项目文件 转换概述 Xylophone.java transformations.zip 动画基础知识 animations.zip 树动画示例 tree_animation.zip 创建视觉效…

ssl2294-打包【dp练习】

Description 你现在拿到了许多的礼物&#xff0c;你要把这些礼物放进袋子里。你只有一个最多装下V 体积物品的袋子&#xff0c;你不能全部放进去。你也拿不动那么重的东西。你估计你能拿的最大重量为 G。现在你了解了每一个物品的完美值、重量和体积&#xff0c;你当然想让袋子…

《走遍中国》珍藏版(三)

Console.WriteLine("上一本书已经看完&#xff0c;从今天开始看下一本"); System.out.println("《走遍中国》珍藏版"); System.out.println("这本书是关于地理的"); System.out.println("地理往往是和历史进行紧密联系的");长廊的油漆…

Catalog Service - 解析微软微服务架构eShopOnContainers(三)

上一篇我们说了Identity Service&#xff0c;因为其基于IdentityServer4开发的&#xff0c;所以知识点不是很多&#xff0c;今天我们来看下Catalog Service&#xff0c;今后的讲解都会把不同的、重点的拿出来讲&#xff0c;希望大家明白。 源码分析 我们先看下它的目录结构&a…

JavaFX官方教程(十五)之A Xylophone.java

翻译自 Xylophone.java 一个 Xylophone.java 有关说明&#xff0c;请参阅转换类型和示例。 法律条款和版权声明 / **版权所有&#xff08;c&#xff09;2010,2014&#xff0c;Oracle和/或其附属公司。* 版权所有。使用须遵守许可条款。**此文件可通过以下许可证获得并获得许…

索引,事务,视图

索引 此时是要获取所有的数据&#xff0c;是否有索引作用不大 select * from emp – 因为数据库以及自动的给主键列empno创建了索引&#xff0c;查询条件中出现empno&#xff0c;自动使用索引进行查询 – 是否使用索引&#xff0c;语句没有区别 select * from emp where empno…

配置环境变量 path

原理 根据windows系统在查找可执行程序的原理&#xff0c;可以将java工具所在路径定义到path 环境变量中&#xff0c;让系统帮我们去找运行执行的程序。 配置方法 我的电脑–属性–高级系统设置–环境变量 编辑 path 环境变量&#xff0c;在变量值开始处加上java工具所在目录…

ssl2863-石子合并【dp练习】

Description 在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆&#xff0c;并将新的一堆石子数记为该次合并的得分。请设计一个程序&#xff0c;计算出将N堆石子合并成一堆的最小得分。 Input 每组数据第1行为一个…