.NET手记-Autofac进阶(注册的概念 Registering Concepts)
通过创建ContainerBuilder并配置暴露的service(接口或者类型)来使用Autofac注册我们的组件。
组件(Components) 可以通过反射, 对象实例,或者lambda表达式来创建. ContainerBuilder有一系列的Register()方法来实现组件的注册。
ContainerBuilder中每个组件都能通过As()方法来暴露他们一个或多个service.
// Create the builder with which components/services are registered.
var builder = new ContainerBuilder(); // Register types that expose interfaces...
builder.RegisterType<ConsoleLogger>().As<ILogger>(); // Register instances of objects you create...
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>(); // Register expressions that execute to create objects...
builder.Register(c => new ConfigReader("mysection")).As<IConfigReader>(); // Build the container to finalize registrations
// and prepare for object resolution.
var container = builder.Build(); // Now you can resolve services using Autofac. For example,
// this line will execute the lambda expression registered
// to the IConfigReader service.
using(var scope = container.BeginLifetimeScope())
{
var reader = container.Resolve<IConfigReader>();
}
反射组件 Reflection Components
通过类型注册
通过反射生成组件最典型的方法是通过类型注册:
var builder = new ContainerBuilder();
builder.RegisterType<ConsoleLogger>();
builder.RegisterType(typeof(ConfigReader));
当使用基于反射的组件时,Autofac会自动使用容器中最可能获取到的参数来构造实例你的类。
例如,你的类有3个构造函数
public class MyComponent
{
public MyComponent() { /* ... */ }
public MyComponent(ILogger logger) { /* ... */ }
public MyComponent(ILogger logger, IConfigReader reader) { /* ... */ }
}
现在使用如下方法注册你的组件:
var builder = new ContainerBuilder();
builder.RegisterType<MyComponent>();
builder.RegisterType<ConsoleLogger>().As<ILogger>();
var container = builder.Build(); using(var scope = container.BeginLifetimeScope())
{
var component = container.Resolve<MyComponent>();
}
当你解析你的组件时,Autofac发现你已经注册了ILogger,但是没有注册IConfigReader。在这个例子中,第二个构造函数会被执行,因为容器中具有最符合的参数。
注意:任何你注册的Type必须都是实类型,这意味着你不能直接注册抽象类或者接口。应为在解析组件时,对象可能会被new实例化,而接口或者抽象类是无法直接实例化的。
指定构造函数 Specifying a Constructor
你可以通过方法UsingConstructor手动指定使用哪个构造函数,其参数为指定构造函数的参数类型。
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>();
注意你提供的参数必须能在容器中获取,不然会出现错误。
实例组件 Instance Components
在很多情况下,你可能想要预先生成对象实例并将它注册到容器中。你可以通过使用RegisterInstance方法来实现:
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>();
当你这么做的时候,一些事情需要被考虑到。Autofac会自动处理对象的释放,但是你很可能想自己控制对象的生命周期,而不是让Autofac调用对象Dispose方法。在这种情况下,你需要使用ExternallyOwned方法:
var output = new StringWriter();
builder.RegisterInstance(output)
.As<TextWriter>()
.ExternallyOwned();
当我们集成Autofac到现有项目中时,可能会存在容器中一些组件用到的对象的单例写法。RegisterInstance()也用来处理这种情况,你可以通过容器来注册它们,而不是直接使用它们:
builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();
这确保了单例最后会被排除,并使用容器托管的对象来替代他。
表达式组件 Lambda Expression Components
反射是创建组件相当好的默认选择,尽管当组件创建逻辑超出简单构造函数调用后,事情可能会变混乱。
Autofac支持通过委托或者Lambda表达式来创建组件:
builder.Register(c => new A(c.Resolve<B>()));
提供的参数c是一个组件上下文对象(IComponentContext),在上下文中创建组件。你可以通过它从容器中解析出其他的值来辅助创建你的组件。使用它而不是使用闭包去访问容器是很重要的,为了层叠容器能够被正确支持。
使用此上下文参数能够满足额外的依赖项。在这个例子中,类型A构造函数要求的B类型参数可能还会依赖其他类型参数。表达式创建的组件暴露的默认服务是通过表达式返回类型来推断的。
下面会给出一些例子:
复杂参数
builder.Register(c => new UserSession(DateTime.Now.AddMinutes()));
属性注入
builder.Register(c => new UserSession(DateTime.Now.AddMinutes()));
通过参数值选择实现方式
builder.Register<CreditCard>(
(c, p) =>
{
var accountId = p.Named<string>("accountId");
if (accountId.StartsWith(""))
{
return new GoldCard(accountId);
}
else
{
return new StandardCard(accountId);
}
});
在这个例子中,CreditCard被两个类实现,分别是GoldenCard和StandardCard,哪种类型被实例取决于输入的卡号。
参数通过可选构造参数p来传入,注册方式可能像这样:
var card = container.Resolve<CreditCard>(new NamedParameter("accountId", ""));
范型组件
Autofac支持范型,通过使用RegisterGeneric()方法:
builder.RegisterGeneric(typeof(NHibernateRepository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
当一个匹配的Service类型被请求时,容器会自动映射它到一个相近的实现类型:
// Autofac将会返回NHibernateRepository<Task>类型
var tasks = container.Resolve<IRepository<Task>>();
指定类型服务的注册将会覆盖掉范型版本。
服务 vs 组件 Services vs. Components
当注册组件时,我们需要告诉Autofac组件暴露了哪种服务。大多数情况下,会暴露组件自身的类型。
// This exposes the service "CallLogger"
builder.RegisterType<CallLogger>();
组件仅能被其暴露的服务来解析出实例,这就意味着如下:
// This will work because the component
// exposes the type by default:
scope.Resolve<CallLogger>(); // 这个将会失败
// tell the registration to also expose
// the ILogger interface on CallLogger:
scope.Resolve<ILogger>();
你也可以使用任何数量的服务来暴露你的组件:
builder.RegisterType<CallLogger>()
.As<ILogger>()
.As<ICallInterceptor>();
你可以通过你暴露的服务来解析出组件实例,但这同时意味着默认服务(组件自身类型)将被覆盖:
// These will both work because we exposed
// the appropriate services in the registration:
scope.Resolve<ILogger>();
scope.Resolve<ICallInterceptor>(); // 失败
// 默认服务被覆盖
scope.Resolve<CallLogger>();
如果你想为组件暴露一系列服务,同时自身类型仍然可用,你需要使用AsSelf方法:
builder.RegisterType<CallLogger>()
.AsSelf()
.As<ILogger>()
.As<ICallInterceptor>();
现在所有服务均可以解析:
// These will all work because we exposed
// the appropriate services in the registration:
scope.Resolve<ILogger>();
scope.Resolve<ICallInterceptor>();
scope.Resolve<CallLogger>();
默认注册 Default Registrations
如果有多个提供相同service的组件被注册,Autofac默认使用最后注册的组件。
builder.Register<ConsoleLogger>().As<ILogger>();
builder.Register<FileLogger>().As<ILogger>();
在这个例子中,FileLogger将会成为ILogger的默认组件提供者,因为它是最后注册的。
为了改写这种行为,使用PreserveExistingDefaults()来修改:
builder.Register<ConsoleLogger>().As<ILogger>();
builder.Register<FileLogger>().As<ILogger>().PreserveExistingDefaults();
在这种情况下,ConsoleLogger将会成为默认组件提供者。
配置文件注册 Configuration of Registrations
你可以使用定义的XML或者代码模块(Module)来实现孕事批量注册或者更改。也可以使用Autofac modules进行一些动态注册生成或者条件注册逻辑。具体请看:http://autofac.readthedocs.org/en/latest/configuration/index.html
动态注册 Dynamically-Provided Registrations
Autofac modules是最简单的方式来引入动态注册逻辑或简单交叉特性。例如,你可以使用module动态地附加一个Log4net实例到解析出的一个service上。请看:http://autofac.readthedocs.org/en/latest/examples/log4net.html
.NET手记-Autofac进阶(注册的概念 Registering Concepts)的更多相关文章
- [翻译] Autofac 中注册的概念
原文链接:http://docs.autofac.org/en/latest/register/registration.html 所谓注册组件,是指创建 ContainerBuilder 的实例,并 ...
- EF6CodeFirst+MVC5+Autofac泛型注册 入门实例
贴一个EF6 CodeFirst模式结合MVC5和Autofac(泛型注册)的一个入门实例 网上类似的例子实在太少,最近自己也有用到这一块的知识,总结了一下,不要让后人踩了自己踩过的坑. 1:新建三个 ...
- .NET手记-Autofac进阶(传递注册参数 Passing Parameters to Register)
当你注册组件时,可以为组件服务传入一系列参数,用于服务解析时使用. 可使用的参数类型 Available Parameter Types Autofac提供了集中参数匹配类别: NamedParame ...
- .NET手记-Autofac进阶(属性和方法注入 Property and Method Injection)
尽管构造函数参数注入是传递参数值给当前构造的组件的优先方式,但是你也可以使用属性或者方法注入来提供参数值. 属性注入使用可写入的变量而不是构造函数参数来完成注入.方法注入则通过方法来设置依赖项. 属性 ...
- 【反射】——Autofac 类型注册
Autofac是.net界一款轻量化的IOC组件,使用Autofac可以帮助完成代码中很多依赖注入工作.在以前文章中,介绍过Autofac的配置过程(http://www.cnblogs.com/Jn ...
- autofac如何注册静态方法里的接口对象
标题可能是不准确的,因为我不知道如何描述.不知道的原因,是对依赖注入一知半解. Autofac可以自动注册对象实例到接口,人所尽知.而在asp.net mvc中,这个实例化的工作,通常在每个控制器的构 ...
- AI - 概念(Concepts)
01 - AI.ML与DL的关系 从涵盖范围上来讲,人工智能(AI)大于机器学习(ML)大于深度学习(DL) 人工智能(AI):能够感知.推理.行动和适应的程序: 机器学习(ML):能够随着数据量的增 ...
- Autofac官方文档翻译--一、注册组件--1注册概念
官方文档:http://docs.autofac.org/en/latest/register/registration.html 一.注册概念 使用Autofac 注册组件,通过创建一个Contai ...
- Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):1.类型注册]
前言 Autofac Autofac是一套高效的依赖注入框架. Autofac官方网站:http://autofac.org/ Autofac在Github上的开源项目:https://github. ...
随机推荐
- linux下redis4.0.2集群部署(利用Ruby脚本命令)
一.原生命令方式和Ruby脚本方式区别 利用Ruby脚本部署和用原生命令部署,节点准备的步骤都是一样的,节点启动后的握手,以及主从.槽分配,利用Ruby脚本一步就能完成,利用原生命令需要一步一步地执行 ...
- 秦殇 xbm buffer
秦殇的图片是封装在lib文件中的, 而且格式为xbm, xbm具体的结构
- mysql修改删除You can't specify target table for update in FROM clause的问题
表中出现重复数据,需要删除重复数据,只保留一条 DELETE FROM crm_participant WHERE id IN ( SELECT c.id cid FROM crm_participa ...
- 配置MQTT服务器
第一步:下载一个Xshell 链接:https://pan.baidu.com/s/16oDa5aPw3G6RIQSwaV8vqw 提取码:zsb4 打开Xshell 前往MQTT服务器软件下载地址: ...
- Jupyter Notebook 的快捷键
原文:http://blog.csdn.net/lawme/article/details/51034543 Jupyter Notebook 的快捷键 Jupyter Notebook 有两种键盘输 ...
- Linux下安装Hadoop
第一步: Hadoop需要JAVA的支持,所以需要先安装JAVA 查看是否已安装JAVA 查看命令: java -version JRE(Java Runtime Environment),它是你运行 ...
- node.js中process进程的概念和child_process子进程模块的使用
进程,你可以把它理解成一个正在运行的程序.node.js中每个应用程序都是进程类的实例对象. node.js中有一个 process 全局对象,通过它我们可以获取,运行该程序的用户,环境变量等信息. ...
- 洛谷1345 [USACO5.4]奶牛的电信Telecowmunication
原题链接 最小割点数转换成最小割边数的模板题(不过这数据好小). 每个点拆成两个点,连一条容量为\(1\)的边,原图的边容量定为\(+\infty\),然后跑最大流即可. 这里用的是\(Dinic\) ...
- ABP Quartz 作业调度第三篇
1.第一步安装Abp.Quartz ,把他安装到核心层 核心模块添加对quarz的依赖, 领域层创建firstjob类 public class FirstJob : JobBase, ITransi ...
- 2019.02.21 bzoj1249: SGU277 HERO 动态凸包(set+凸包)
传送门 题意:动态插入点,维护凸包面积. 思路:用setsetset维护极角序来支持面积查询即可. 然后注意选原点的时候要从初始三个点随机平均系数来避免精度误差. 代码: #include<bi ...