官方文档:http://docs.autofac.org/en/latest/register/registration.html

一、注册概念

  使用Autofac 注册组件,通过创建一个ContainerBuilder并且告知builder 哪些组件公开哪些服务。

  组件由反射(通过注册一个特殊的.net 类型或者开放的泛型)创建;通过提供现成的实例(你已创建的一个对象实例)创建;或由lambda表达式创建。ContainerBuilder有一系列的Register()方法,允许你实现以上这些设置。

  通过使用ContainerBuilder中的As()方法,每个组件公开一个或多个服务。

// 创建组件/服务注册的容器
var builder = new ContainerBuilder(); // 注册类型公开接口
builder.RegisterType<ConsoleLogger>().As<ILogger>(); // 注册你创建的对象实例
var output = new StringWriter();
builder.RegisterInstance(output).As<TextWriter>(); // 注册执行创建对象的表达式
builder.Register(c => new ConfigReader("mysection")).As<IConfigReader>(); // 编译容器完成注册且准备对象解析
var container = builder.Build(); // 现在你可以使用 Autofac 解析服务. 例如,这行将执行注册的lambda表达式对于 IConfigReader 服务.
using(var scope = container.BeginLifetimeScope())
{
var reader = container.Resolve<IConfigReader>();
}

1、反射组件

1.1通过类型注册

通过反射生成的组件通常是由类型注册的:
var builder = new ContainerBuilder();
builder.RegisterType<ConsoleLogger>();
builder.RegisterType(typeof(ConfigReader));

当使用基于反射的组件,Autofac自动为你的类,匹配拥有最多参数的构造函数,此参数可以从容器中获得。

例如,你有一个拥有三个构造函数的类:

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。在这种情况下,第二个构造函数将会被选择,因为这是在容器中能够找到的拥有最多参数的一个构造函数。

基于反射的组件需要注意:由RegisterType注册的组件类型必须是一个具体类型。虽然组件可以公开抽象类和接口作为服务,但是你不能注册一个抽象类/接口 组件。如果你仔细想想是有道理的:在Autofac内部,Autofac创建一个你注册的对象实例。你不能new 一个抽象类或一个接口。你必须有一个实现对吧。

1.2指定一个构造函数

您可以手动选择一个特定的构造函数,来使用和覆盖注册组件自动选择的构造函数,使用UsingConstructor方法和一系列类型来表示构造函数的参数类型:

builder.RegisterType<MyComponent>()
.UsingConstructor(typeof(ILogger), typeof(IConfigReader));

请注意,在解析时,您仍然需要提供必要的参数,否则,在你尝试解析对象时将出现一个错误。你可以在注册时传递参数或者在解析时传递参数。

2、实例组件

有时候,您可能希望提前生成一个对象的实例,并将它添加到容器供组件注册使用。你可以这样做,使用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集成到一个现有的应用程序(一个单例实例已经存在且需要在容器中作为组件使用)时,注册提供的实例也派上了用场,而不是把这些组件直接绑到单例上,它可以在容器中注册为一个实例:

builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();

这将确保静态单例可以最终被淘汰,取而代之的是一个容器管理。

默认服务通过一个具体类型的实例公开。请参阅下面的“服务和组件”。

3、Lambda表达式组件

反射对于组件创建是一种非常好的默认选择。当组件创建逻辑不只是一个简单的构造函数调用时,事情将变得混乱。

Autofac 接受一个委托或者lambda表达式用于组件创建:

builder.Register(c => new A(c.Resolve<B>()));

表达式提供的参数c是组件上下文(一个IComponentContext对象) ,此处该组件被创建。您可以使用它来解析来自于容器的其他组件,从而帮助你创建组件。重要的是使用它,而不是一个闭包来访问容器,以便正确的支持内嵌容器和自定义清理。

使用上下文参数可以使用额外的依赖关系——在这个例子中,A需要参数为类型B的构造函数,可能有额外的依赖关系。

通过expression-created组件提供的默认服务是推断表达式的返回类型。

下面是一些需求的例子,通过反射组件创建非常笨拙,但是通过lambda表达式非常漂亮的处理了。

  • 复杂参数
构造函数参数不能总是用简单的常量值声明。而不使用XML配置语法构造某种类型的值,使用代码:
builder.Register(c => new UserSession(DateTime.Now.AddMinutes(25)));

当然,会话到期你可能想在配置文件中指定一些事情。

  • 属性注入
虽然Autofac 提供了一流的属性注入,你也可以使用表达式和属性初始化来填充特性:
builder.Register(c => new A(){ MyB = c.ResolveOptional<B>() });

这个ResolveOptional 方法将尝试解析值,但如果服务没有被注册,不会抛出一个异常。(你将得到一个异常如果服务被注册但是属性没有被解析)。这是解析服务的其中一种方式。

在大多数情况下不推荐使用属性注入。替代空对象模式,重新加载构造函数或构造函数参数的默认值,可以创造更清洁、“不变”的组件,可使用构造函数注入依赖项。
  • 通过参数值选择一个实现(Selection of an Implementation by Parameter Value)
分离组件创建最大的好处就是具体类型可以变化,这通常是在运行是完成,而不仅仅是在配置时:
builder.Register<CreditCard>(
(c, p) =>
{
var accountId = p.Named<string>("accountId");
if (accountId.StartsWith("9"))
{
return new GoldCard(accountId);
}
else
{
return new StandardCard(accountId);
}
});

在这个例子中,CreditCard 通过两个类实现,GoldCard and StandardCard哪个类被实例化依赖于运行时提供的accountId。

在这个例子中,创建方法通过第二个参数p提供参数。

使用下面代码进行注册:

var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));
如果使用委托创建CreditCard 实例声明和一个委托工厂,可以获得一个清洁,类型安全的语法。 

4、公开通用组件(Open Generic Components)

Autofac 支持开放的泛型类型,使用RegisterGeneric()构造方法:

builder.RegisterGeneric(typeof(NHibernateRepository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
当容器需要一个匹配的服务类型时,autofac 将会映射到一个等价的接近的实现类型的版本。
// Autofac will return an NHibernateRepository<Task>
var tasks = container.Resolve<IRepository<Task>>();
注册的专有服务类型(例如IRepository <Person>)将会重写通用的版本。

5、服务和组件(Services vs. Components)

当你注册组件时,必须告诉autofac组件公开哪个服务,默认,大多数注册仅仅公开自己作为注册类型。
// This exposes the service "CallLogger"
builder.RegisterType<CallLogger>();

组件只能被它们公开的服务解析,在这个简单的示例中,它意味着:

// 这个将会正常工作,因为组件默认公开此类型
scope.Resolve<CallLogger>(); // 这个不会工作,因为我们没有注册也没有公开ILogger接口
scope.Resolve<ILogger>();
你可以用任意数量的服务公开组件。
builder.RegisterType<CallLogger>()
.As<ILogger>()
.As<ICallInterceptor>();
一旦公开一个服务,可以解析基于服务的组件。但是请注意,一旦你公开一个组件作为一个特定的服务,默认的服务(组件类型)将被覆盖:
// 这些都将工作,因为我们在注册中公开了对应的服务
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>();

6、默认注册(Default Registrations)

如果多个组件公开同一个服务,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将作为默认的ILogger服务提供者,因为最后注册的FileLogger使用了PreserveExistingDefaults()。

7、注册配置(Configuration of Registrations)

可以使用XML或编程配置“modules”来提供一组注册或者在运行时改变注册。也可以使用Autofac modules提供一些动态注册生成或条件注册逻辑。

8、提供动态注册(Dynamically-Provided Registrations)

Autofac modules 对于介绍动态注册逻辑是最简单的方法。你可以在解析的时候使用一个module 为一个服务动态的添加一个log4net 日志实例,
如果你需要更多的动态特性,如添加一个新的隐式关系类型的支持,你可能想要用先进的理念检查注册源部分。

Autofac官方文档翻译--一、注册组件--1注册概念的更多相关文章

  1. Autofac官方文档翻译--一、注册组件--4组件扫描

    官方文档:http://docs.autofac.org/en/latest/register/scanning.html Autofac 组件扫描 在程序集中Autofac 可以使用约定来找到并注册 ...

  2. Autofac官方文档翻译--一、注册组件--2传递注册参数

    官方文档:http://docs.autofac.org/en/latest/register/parameters.html 二.Autofac 传递注册参数 当你注册组件时能够提供一组参数,可以在 ...

  3. Autofac官方文档翻译--二、解析服务--2隐式关系类型

    Autofac 隐式关系类型 Autofac 支持自动解析特定类型,隐式支持组件与服务间的特殊关系.要充分利用这些关系,只需正常注册你的组件,但是在使用服务的组件或调用Resolve()进行类型解析时 ...

  4. Autofac官方文档翻译--二、解析服务--1解析参数传递

    Autofac 传递解析参数 注册组件公开相应的服务之后,你可以从container构造器和子lifetime scopes 中解析服务.使用Resolve()方法来实现: var builder = ...

  5. Autofac官方文档翻译--一、注册组件--3属性和方法注入

    官方文档:http://docs.autofac.org/en/latest/register/prop-method-injection.html Autofac 属性和方法注入 虽然构造函数参数注 ...

  6. Ioc容器Autofac系列(3)-- 三种注册组件的方式

    简单来说,所谓注册组件,就是注册类并映射为接口,然后根据接口获取对应类,Autofac将被注册的类称为组件. 虽然可像上篇提到的一次性注册程序集中所有类,但AutoFac使用最多的还是单个注册.这种注 ...

  7. Autofac注册组件详解

    注册概念:我们通过创建 ContainerBuilder 来注册 组件 并且告诉容器哪些 组件 暴露了哪些 服务.组件 可以通过 反射 创建; 通过提供现成的 实例创建; 或者通过 lambda 表达 ...

  8. Vue组件-组件的注册

    注册组件 全局组件 注册组件就是利用Vue.component()方法,先传入一个自定义组件的名字,然后传入这个组件的配置. Vue.component('my-component', { templ ...

  9. springcloud组件之注册中心eureka学习

    eureka的高可用 微服务架构中最核心的部分是服务治理,服务治理最基础的组件是注册中心.随着微服务架构的发展,出现了很多微服务架构的解决方案,其中包括我们熟知的Dubbo和Spring Cloud. ...

随机推荐

  1. 【2014广州市选day1】JZOJ2020年9月12日提高B组T3 消除游戏

    [2014广州市选day1]JZOJ2020年9月12日提高B组T3 消除游戏 题目 Description 相信大家玩过很多网络上的消除类型的游戏,一般来说就是在一个大拼图内找出相同的部分进行最大程 ...

  2. this大全,还有谁??????!!!!!!!

    this在函数调用时创建,一般的对象没有this,全局window可以理解为一个函数,他有一个全局this JavaScript 语言之所以有this的设计,跟内存里面的数据结构有关系. 函数里thi ...

  3. PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

    注:网上搜来的快照,暂未验证 在java代码中请求https链接的时候,可能会报下面这个错误javax.net.ssl.SSLHandshakeException: sun.security.vali ...

  4. 倾斜摄影实景三维在智慧工厂 Web 3D GIS 数字孪生应用

      数字化推动钢铁工业转型升级 数字时代,随着数字地球,数字中国,数字工厂等数字化建设的不断深入,以地理信息系统(Geographic Information System, GIS)为基础,融合大数 ...

  5. Python特殊序列\d能匹配哪些数字?

    在缺省语言环境下,老猿对\d的匹配范围做了个测试,下面的数字包含半角数字.全角数字.中文数字,测试语句如下: >>> m=re.search(r'(\d*)(\D*)(\d*)',' ...

  6. PyQt(Python+Qt)学习随笔:formLayout的layoutRowWrapPolicy属性

    Qt Designer的表单布局(formLayout)中,layoutRowWrapPolicy用于控制表单布局中表单行的标签和输入部件之间是否换行.如图: 上图中蓝色标记圈起来的下拉列表数据是其可 ...

  7. 如何利用Excel快速批量生成想要的代码

    如何利用Excel快速批量生成想要的代码 使用场景 在HTML DOM Video 对象这个页面 我想要将所有的中文描述和对应的属性(共32个属性)打印出来--console.log(descript ...

  8. [GXYCTF2019] MISC杂项题

    buuoj复现 1,佛系青年 下载了之后是一个加密的txt文件和一张图片 分析图片无果,很讨厌这种脑洞题,MISC应该给一点正常的线索加部分脑洞而不是出干扰信息来故意让选手走错方向,当时比赛做这道题的 ...

  9. jq中$(function(){})和js中window.onload区别

    先看下执行代码: $(function(){   console.log("jq");}) $(function(){   console.log("jq1") ...

  10. Panda 交易所视点观察!区块链金融应用迎新规,哪些版块受影响?

    Panda交易所获悉,近日央行下发推动<区块链技术规范应用的通知>(以下简称"通知")及<区块链技术金融应用评估规则>(以下简称"规则" ...