Getting Started
入门指南
The basic pattern for integrating Autofac into your application is:
- Structure your app with inversion of control (IoC) in mind.
- Add Autofac references.
- At application startup…
- Create a ContainerBuilder.
- Register components.
- Build the container and store it for later use.
- During application execution…
- Create a lifetime scope from the container.
- Use the lifetime scope to resolve instances of the components.
将Autofac集成到你的应用中基本步骤如下:
- 考虑使用IoC构建您的应用程序.
- 添加Autofac引用.
- 在程序启动的地方…
- 创建对象ContainerBuilder.
- 注册组件.
- 生成容器并存储以供以后使用.
- 在应用程序执行期间…
- 从容器中创建一个生命周期.
- 使用生命周期获取组件的实例.
This getting started guide walks you through these steps for a simple console application. Once you have the basics down, you can check out the rest of the wiki for more advanced usage and integration information for WCF, ASP.NET, and other application types.
本入门指南将指导您完成一个简单的控制台应用程序的这些步骤。. 一旦掌握了基本知识,您可以查看wiki的其他部分比如:高级用法,与WCF, ASP.NET, 其它类型的程序的集成方法.
Structuring the Application
构建应用程序
The idea behind inversion of control is that, rather than tie the classes in your application together and let classes “new up” their dependencies, you switch it around so dependencies are instead passed in during class construction. Martin Fowler has an excellent article explaining dependency injection/inversion of control if you want more on that.
Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制. 如果你想了解更多Martin Fowler 有一篇很好的文章,解释了依赖注入/控制的反转 .
For our sample app, we’ll define a class that writes the current date out. However, we don’t want it tied to the Console
because we want to be able to test the class later or use it in a place where the console isn’t available.
对于示例应用程序,我们将定义一个写入当前日期的类。但是,我们不希望它与控制台绑定,因为我们希望稍后能够测试该类,或者在控制台不可用的地方使用它。
We’ll also go as far as allowing the mechanism writing the date to be abstracted, so if we want to, later, swap in a version that writes tomorrow’s date, it’ll be a snap.
我们还将尽可能允许抽象化编写日期的机制,所以如果我们以后想交换一个写明天日期的版本,那就很简单了。
We’ll do something like this:
如下为示例代码
using System;
namespace DemoApp
{
// This interface helps decouple the concept of
// "writing output" from the Console class. We
// don't really "care" how the Write operation
// happens, just that we can write.
public interface IOutput
{
void Write(string content);
}
// This implementation of the IOutput interface
// is actually how we write to the Console. Technically
// we could also implement IOutput to write to Debug
// or Trace... or anywhere else.
public class ConsoleOutput : IOutput
{
public void Write(string content)
{
Console.WriteLine(content);
}
}
// This interface decouples the notion of writing
// a date from the actual mechanism that performs
// the writing. Like with IOutput, the process
// is abstracted behind an interface.
public interface IDateWriter
{
void WriteDate();
}
// This TodayWriter is where it all comes together.
// Notice it takes a constructor parameter of type
// IOutput - that lets the writer write to anywhere
// based on the implementation. Further, it implements
// WriteDate such that today's date is written out;
// you could have one that writes in a different format
// or a different date.
public class TodayWriter : IDateWriter
{
private IOutput _output;
public TodayWriter(IOutput output)
{
this._output = output;
}
public void WriteDate()
{
this._output.Write(DateTime.Today.ToShortDateString());
}
}
}
Now that we have a reasonably structured (if contrived) set of dependencies, let’s get Autofac in the mix!
现在我们有了一个合理的结构化(如果设计的)依赖集,让我们和Autofac结合使用!
Add Autofac References
增加Autofac引用
The first step is to add Autofac references to your project. For this example, we’re only using core Autofac. Other application types may use additional Autofac integration libraries..
第一个是引用Autofac到你的项目中 .例如, 我们使用 core 版本的Autofac. 其它类型的程序引用对应类型版本的Autofac.
The easiest way to do this is through NuGet. The “Autofac” package has all the core functionality you’ll need.
最简单的方法是通过NuGet。“Autofac”软件包具有您所需的所有核心功能。
Application Startup
应用程序的启动
At application startup, you need to create a ContainerBuilder and register your components with it. A component is an expression, .NET type, or other bit of code that exposes one or more services and can take in other dependencies.
在应用程序启动时,您需要创建ContainerBuilder生成器并注册你的组件。一个组件是一个表达式,.NET类型,或其他实现了依赖项的公开一个或多个服务。
In simple terms, think about a .NET type that implements an interface, like this:
简单地说,一个.Net类实现一个接口,如下所示:
public class SomeType : IService
{
}
You could address that type in one of two ways:
您可以用两种方式之一来解决该类型问题:
- As the type itself,
SomeType
- As the interface, an
IService
- 类型本身,
SomeType
- 接口,
IService
In this case, the component is SomeType
and the services it exposes are SomeType
and IService
.
在这种情况下,组件是SomeType,它公开的服务是SomeType
和IService
。
In Autofac, you’d register that with a ContainerBuilder
something like this:
在Autofac中,你可以注册一个ContainerBuilder 如下代码所示:
// Create your builder.
var builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder.RegisterType<SomeType>().As<IService>();
// However, if you want BOTH services (not as common)
// you can say so:
builder.RegisterType<SomeType>().AsSelf().As<IService>();
For our sample app, we need to register all of our components (classes) and expose their services (interfaces) so things can get wired up nicely.
对于我们的示例应用程序,我们需要注册我们所有的组件(类)并公开它们的服务(接口),以便事情可以很好地连接起来。
We also need to store the container so it can be used to resolve types later.
我们还需要存储该容器,以便它以后可以用于解析类型。
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();
// The WriteDate method is where we'll make use
// of our dependency injection. We'll define that
// in a bit.
WriteDate();
}
}
}
Now we have a container with all of the components registered and they’re exposing the proper services. Let’s make use of it.
现在我们有了一个注册了所有组件的容器,它们正在公开适当的服务。让我们好好利用一下它吧。
Application Execution
应用程序的执行
During application execution, you’ll need to make use of the components you registered. You do this by resolving them from a lifetime scope.
在应用程序执行期间,您需要使用您注册的组件。您可以组件的生命周期内解析它并使用。
The container itself is a lifetime scope, and you can technically just resolve things right from the container. It is not recommended to resolve from the container directly, however.
容器本身有一个生命周期,技术上可以从容器中直接获取组件。但是,不建议直接从容器中解析。
When you resolve a component, depending on the instance scope you define, a new instance of the object gets created. (Resolving a component is roughly equivalent to calling “new” to instantiate a class. That’s really, really oversimplifying it, but from an analogy perspective it’s fine.) Some components may need to be disposed (like they implement IDisposable
) - Autofac can handle disposing those components for you when the lifetime scope is disposed.
解析组件时,根据定义的实例范围,将创建对象的新实例。(解析一个组件大致相当于调用“new”来实例化一个类。这真的,真的太过简化了,但从类比的角度来看还可以。)某些组件可能需要释放(比如实现接口IDisposable
)——Autofac可以在处理生命周期范围时为您处理处理这些组件。
However, the container lives for the lifetime of your application. If you resolve a lot of stuff directly from the container, you may end up with a lot of things hanging around waiting to be disposed. That’s not good (and you may see a “memory leak” doing that).
但是,该容器将使用应用程序的生命周期。如果你直接从容器中解决了很多东西,你可能会有很多东西等待被处理。这并不好(你可能会看到“内存泄漏”)。
Instead, create a child lifetime scope from the container and resolve from that. When you’re done resolving components, dispose of the child scope and everything gets cleaned up for you.
相反,从容器创建子生命周期范围,并从其解析。完成组件解析后,处理子范围,并为您清理所有内容。
(When you’re working with the Autofac integration libraries, this child scope creation is largely done for you so you don’t have to think about it.)
(在使用Autofac集成库时,此子生命周期已经为你完成了大部分功能,因此您不必考虑它。)
For our sample app, we’ll implement the “WriteDate” method to get the writer from a scope and dispose of the scope when we’re done.
对于我们的示例应用程序,我们将实现“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()
{
// Create the scope, resolve your IDateWriter,
// use it, then dispose of the scope.
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IDateWriter>();
writer.WriteDate();
}
}
}
}
Now when you run your program…
现在,运行你的程序
- The
WriteDate
method creates a lifetime scope from which it can resolve dependencies. It does this to avoid any memory leaks - ifIDateWriter
or its dependencies are disposable, they will be automatically disposed when the scope is disposed. - The
WriteDate
method manually resolves anIDateWriter
from the lifetime scope. (This is “service location.”) Internally…- Autofac sees that
IDateWriter
maps toTodayWriter
so starts creating aTodayWriter
. - Autofac sees that the
TodayWriter
needs anIOutput
in its constructor. (This is “constructor injection.”) - Autofac sees that
IOutput
maps toConsoleOutput
so creates a newConsoleOutput
instance. - Autofac uses the new
ConsoleOutput
instance to finish constructing theTodayWriter
. - Autofac returns the fully-constructed
TodayWriter
forWriteDate
to consume.
- Autofac sees that
- The call to
writer.WriteDate()
goes to the brand newTodayWriter.WriteDate()
since that’s what was resolved. - The Autofac lifetime scope is disposed. Any disposable items that were resolved from that lifetime scope are also disposed.
WriteDate
方法创建一个生命周期范围,它可以从中解决依赖关系。它这样做是为了避免任何内存泄漏——如果IDateWriter
或其依赖项是一次性的,它们将在释放范围时自动释放。WriteDate
方法从生命周期范围内手动解析IDateWriter
。(这是“service location.”)内部信息…- Autofac 查看
IDateWriter
映射TodayWriter
关系,创建了一个TodayWriter
. - Autofac 查看
TodayWriter
需要IOutput
在构造函数中. (这是 “构造注入.”) - Autofac 查找
IOutput
映射ConsoleOutput
关系,创建了 一个ConsoleOutput
实例. - Autofac 使用
ConsoleOutput
完成构造TodayWriter
. - Autofac 返回构造好的
TodayWriter
给WriteDate使用
.
- Autofac 查看
- 这个调用
writer.WriteDate()
为新的TodayWriter.WriteDate()
从而解决了该问题. - Autofac 生命周期范围已被释放. 任何可以释放的子项也会相应的被释放.
Later, if you want your application to write a different date, you could implement a different IDateWriter
and then change the registration at app startup. You don’t have to change any other classes. Yay, inversion of control!
稍后,如果希望应用程序编写不同的日期,则可以实现不同的 IDateWriter
,然后在应用程序启动时更改注册。您不必更改任何其他类。很帅,控制反转!
Note: generally speaking, service location is largely considered an anti-pattern (see article). That is, manually creating scopes everywhere and sprinkling use of the container through your code is not necessarily the best way to go. Using the Autofac integration libraries you usually won’t have to do what we did in the sample app above. Instead, things get resolved from a central, “top level” location in the application and manual resolution is rare. Of course, how you design your app is up to you.
注:一般来说,服务位置主要被认为是一种反模式的(见文章)。也就是说,在到处手动创建范围,并通过代码零星地使用容器并不一定是最好的方法。使用Autofac集成库,通常不必执行上面示例应用程序中所做的操作。相反,从应用程序中的中央“顶级”位置解决,手动解决很少。当然,你如何设计你的应用程序取决于你自己。
Going Further
更进一步
The sample app gives you an idea of how to use Autofac, but there’s a lot more you can do.
示例应用程序让您了解如何使用Autofac,但您可以做更多。
- Check out the list of integration libraries to see how to integrate Autofac with your application.
- Learn about the ways to register components that add flexibility.
- Learn about Autofac configuration options that allow you to better manage your component registrations.
- 查阅 集成库列表 来查找 Autofac 如何与你的应用程序集成.
- 学会更灵活的 注册组件 .
- 学习 Autofac 配置选项 更好的管理你的组件注册.
Need Help?
需要帮助?
- You can ask questions on StackOverflow.
- You can participate in the Autofac Google Group.
- There’s an introductory Autofac tutorial on CodeProject.
- We have advanced debugging tips if you want to dive deep.
- 你可以在 StackOverflow 上提问.
- 你可以在 Autofac Google Group 练习.
- 这时有相关的 Autofac 材料 .
- 如果你想深入了解,我们有 高级调试指南.
Building from Source
从源码编译
The source code along with Visual Studio project files is available on GitHub. Build instructions and details on contributing can be found in the Contributor Guide.