通过创建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)的更多相关文章

  1. [翻译] Autofac 中注册的概念

    原文链接:http://docs.autofac.org/en/latest/register/registration.html 所谓注册组件,是指创建 ContainerBuilder 的实例,并 ...

  2. EF6CodeFirst+MVC5+Autofac泛型注册 入门实例

    贴一个EF6 CodeFirst模式结合MVC5和Autofac(泛型注册)的一个入门实例 网上类似的例子实在太少,最近自己也有用到这一块的知识,总结了一下,不要让后人踩了自己踩过的坑. 1:新建三个 ...

  3. .NET手记-Autofac进阶(传递注册参数 Passing Parameters to Register)

    当你注册组件时,可以为组件服务传入一系列参数,用于服务解析时使用. 可使用的参数类型 Available Parameter Types Autofac提供了集中参数匹配类别: NamedParame ...

  4. .NET手记-Autofac进阶(属性和方法注入 Property and Method Injection)

    尽管构造函数参数注入是传递参数值给当前构造的组件的优先方式,但是你也可以使用属性或者方法注入来提供参数值. 属性注入使用可写入的变量而不是构造函数参数来完成注入.方法注入则通过方法来设置依赖项. 属性 ...

  5. 【反射】——Autofac 类型注册

    Autofac是.net界一款轻量化的IOC组件,使用Autofac可以帮助完成代码中很多依赖注入工作.在以前文章中,介绍过Autofac的配置过程(http://www.cnblogs.com/Jn ...

  6. autofac如何注册静态方法里的接口对象

    标题可能是不准确的,因为我不知道如何描述.不知道的原因,是对依赖注入一知半解. Autofac可以自动注册对象实例到接口,人所尽知.而在asp.net mvc中,这个实例化的工作,通常在每个控制器的构 ...

  7. AI - 概念(Concepts)

    01 - AI.ML与DL的关系 从涵盖范围上来讲,人工智能(AI)大于机器学习(ML)大于深度学习(DL) 人工智能(AI):能够感知.推理.行动和适应的程序: 机器学习(ML):能够随着数据量的增 ...

  8. Autofac官方文档翻译--一、注册组件--1注册概念

    官方文档:http://docs.autofac.org/en/latest/register/registration.html 一.注册概念 使用Autofac 注册组件,通过创建一个Contai ...

  9. Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):1.类型注册]

    前言 Autofac Autofac是一套高效的依赖注入框架. Autofac官方网站:http://autofac.org/ Autofac在Github上的开源项目:https://github. ...

随机推荐

  1. 微信小程序 验证码倒计时组件

    https://blog.csdn.net/susuzhe123/article/details/80032224

  2. Java虚拟机 内存区域划分

    (图片来自https://www.cnblogs.com/whgk/p/6138522.html) 先从线程私有区开始介绍 虚拟机栈 Java虚拟机栈是由一个个栈帧组成的,当一个方法被调用时,代表这个 ...

  3. Cobbler安装CentOS7系统时报错 What do you want do now?

    问题的根源: 在cobbler服务主机中执行了  createrepo --update  /var/www/cobbler/ks_mirror/CentOS-7-x86_64/ 导致的. cobbl ...

  4. 命名空间 extern的用法 static全局变量

    std是标准库中的命名空间: 关于extern的用法可以参考文献http://blog.163.com/sunjinxia%40126/blog/static/94984879201312145021 ...

  5. SSM框架整合的其它方式

    ---------------------siwuxie095                                 SSM 框架整合的其它方式         1.主要是整合 Spring ...

  6. The Moon and Sixpence摘抄

    I had not yet learnt how contradictory is human nature; I did not know how much pose there is in the ...

  7. [leetcode]52. N-Queens II N皇后

    The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens ...

  8. canvas(五)createPattern

    /** * Created by xianrongbin on 2017/3/9. * 图片填充 */ var dom = document.getElementById('clock'), ctx ...

  9. 设计模式 策略模式2 c++11

    根据需求的不同 选择不同的策略算法 之前是保存的各种策略类的指针 这里直接使用 function  bind 选择对应的算法 代码 // 005.cpp: 定义控制台应用程序的入口点. // #inc ...

  10. 消息模式Toast.makeText的几种常见用法

    Toast 是一个 View 视图,快速的为用户显示少量的信息. Toast 在应用程序上浮动显示信息给用户,它永远不会获得焦点,不影响用户的输入等操作,主要用于 一些帮助 / 提示. Toast 最 ...