立即开始
将Autofac整合到你的应用的基本模式如下:
- 按照控制反转(IoC)的思想构建你的应用程序
- 添加Autofac引用
- 在application启动代码里…
- 创建
ContainerBuilder
对象 - 注册组件
- Build容器并且保存以备用
- 在程序执行阶段
- 从容器创建一个作用域
- 在作用域里获取组件的实例
本向导通过一个简单的控制台应用来介绍上述步骤。一旦你学会了这些步骤,你可以查看wiki的剩余部分来了解更多高级用法,通过点击这里了解WCF, ASP.NET, 和其他应用类型的整合方法。
应用程序构建
控制反转的思想是,在类的构造函数里传递依赖而不是在应用程序里将这些类绑在一起让类自己创建他们的依赖。Martin Fowler写了一篇非常棒的文章是关于依赖注入/控制反转的。如果感兴趣可以去了解一下。
在我们的例子里,我们将定义一个类来输出当前的日期。当然,我们不希望和Console
绑定因为我们想在控制台不可用的情况依然可以测试这个类。
同样,输入日期的方法被定义成抽象的,这样的话如果我们想新增一个输出明天日期的方法就可以直接重载。
我们先定义一段代码:
using System;
namespace DemoApp
{
// 这个接口帮助我们从Console类解耦"输出"方法
// 我们不需要关心怎样输出,只要知道能输出即可
public interface IOutput
{
void Write(string content);
}
// 这里IOutput接口的实现完成向控制台的输出。
// 技术上讲,我们可以实现IOutput接口完成Debug或者Trace或者
// 其他的输出方式
public class ConsoleOutput : IOutput
{
public void Write(string content)
{
Console.WriteLine(content);
}
}
// 这个接口解耦实际输出日期的接口。
// 像IOutput一样,这个处理在后面的接口里抽象化
public interface IDateWriter
{
void WriteDate();
}
// ToadyWriter将上述两个接口进行组合
// 注意这里的构造函数参数是IOutput类型
// 这样这个writer的输出由IOutput的实现决定
// 更进一步说,他实现了WriteDate输出今天的日期
// 你可以再定义一个输出不同格式或者不同日期的方法
public class TodayWriter : IDateWriter
{
private IOutput _output;
public TodayWriter(IOutput output)
{
this._output = output;
}
public void WriteDate()
{
this._output.Write(DateTime.Today.ToShortDateString());
}
}
}
现在我们有一个构造函数来设置依赖,我们来添加Autofac进来吧!
添加Autofac引用
第一步是添加Autofac引用到工程里。在这个例子里,我们只引用Autofac核心库。其他应用程序类型可能会用一些额外的Autofac整合库
最简单的方法是通过NuGet添加。Autofac程序包里包含了所需的所有核心功能。
应用程序启动
在应用程序启动过程中,首先要创建一个ContainerBuilder
并且用它注册你的组件。组件是一个表达式, .NET类型或者其他的一段暴露一个或者多个服务的代码并且可以用在其他的依赖里。
简单来说,就像下面的例子所述,定义一个实现某个接口的.NET类型
public class SomeType : IService
{
}
你可以通过下面两种方法之一来定位这个类型
- 指定类型本身,SomeType
- 指定接口,一个IService
在这个例子里,这个组件是SomeType
,他暴露的服务是SomeType
和IService
.
在Autofac里,你应当用一个ContainerBuilder
来注册他们,如下:
// 创建你的builder
var builder = new ContainerBuilder();
// 通常你只关心这个接口的一个实现
builder.RegisterType<SomeType>().As<IService>();
// 当然,如果你想要全部的服务(不常用),可以这么写:
builder.RegisterType<SomeType>().AsSelf().As<IService>();
在我们的例子里,我们要注册所有的组件(类)并且获取他们的服务(接口),这样这些对象连接起来会更方便
我们还要保存这个容器,这样我们可以在后面用来解析这些类型
using System;
using Autofac;
namespace DemoApp
{
public class Program
{
private static IContainer Container { get; set; }
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<ConsoleOutput>().As<IOutput>();
builder.RegisterType<TodayWriter>().As<IDateWriter>();
Container = builder.Build();
// 我们将在这个方法里使用依赖注入,后面我们会定义它
WriteDate();
}
}
}
现在我们有一个包含了所有组件的容器,而且他们也暴露的相关的服务。我们可以用它们了。
应用程序执行
在应用程序执行阶段,你将要用到这些注册的组件,你可以通过在作用域解析他们来使用。
容器本身是也是一个作用域,而且从技术上讲你可以直接从容器解析对象。尽管如此,我们不提倡这么做。
当你解析了一个组件,一个对象的实例将在你定义的实例范围内被创建.(解析一个组件基本上跟new一个类是等价的。这的确很简单,但是从分析角度来说这是OK的)有些组件可能需要释放(例如实现了IDisposable
接口)- 当作用域释放的时候可以帮你释放这些组件。
当然, 容器在你应用程序的整个作用域内都是存在的。如果你直接从container解析了很多对象,在程序终止时可能会有大量的释放操作将程序挂起。所以不提倡这么做(而且你可能会遇到“内存泄露”的提示)
所以,通过从容器创建一个子作用域范围来解析对象。当你完成对象解析后,释放子作用域可以清除该周期创建的一切事物。
(当你使用一些Autofac整合库)开发时,子作用域已经自动帮你创建了,你无需考虑这些问题。
在这个例子里,我们将在子作用域里实现”WriteDate”方法打印日期并且完成后释放这个作用域
namespace DemoApp
{
public class Program
{
private static IContainer Container { get; set; }
static void Main(string[] args)
{
// ...the stuff you saw earlier...
}
public static void WriteDate()
{
// 创建作用域,解析IDateWriter,使用,然后释放
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IDateWriter>();
writer.WriteDate();
}
}
}
}
当你运行你的程序时…
- WriteDate方法要求Autofac提供
IDateWriter
. - Autofac发现
IDateWriter
映射到TodayWriter
所以创建了一个TodayWriter
对象 - Autofac发现
TodayWriter
构造函数需要IOutput
- Autofac发现
IOutput
映射到ConsoleOutput
,所以创建一个新的ConsoleOutput
的实例 - Autofac使用
ConsoleOutput
实例完成TodayWriter
的创建 - Autofac返回一个完整的
TodayWriter
对象给”WriteDate”来消费
最后,如果你希望你的应用输出一个不同的日期,你可以实现另外一个IDateWriter
然后再app启动的时候改变一下注册过程。你不需要修改任何其他的类。耶,控制反转了!
注意:通常来说,服务定位大多都考虑了反面模式(参考) http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx。就是说,在你的代码里到处分散的手动创建作用域不是最佳的实现方式。使用Autofac整合库以后,你通常不需要做本例中的处理。相反的,对象很少在应用程序的”顶级”位置解析或者在手动解析。当然,怎么设计你的app是由你自己决定的。
更进一步
这个例子告诉你怎么使用Autofac,但是你还需要了解更多的内容
- 查看Autofac整合库列表来了解如何整合Autofac到你的应用程序里
- 学习注册组件的方法提高代码灵活性
- 学习Autofac配置选项更好的管理你的组件注册
需要帮助?
- 你可以在StackOverflow提问
- 你可以参加Autofac Google小组
- CodeProject有一篇Autofac介绍的文章
从源码生成
Visual Studio工程的源码GitHub。编译说明在代码根目录的README里,更多关于工程的信息参考投稿说明.