1. 什么是 Autofac?
Autofac 是一个开源的、高效的 .NET IoC(控制反转)容器。它用于管理类之间的依赖关系,从而带来更松散耦合、更可测试和更易维护的代码。
- 控制反转 (IoC): 是一种设计原则,将对象的创建和绑定责任从对象内部转移到外部容器。
- 依赖注入 (DI): 是实现 IoC 的一种技术,将依赖项通过构造函数、属性或方法"注入"到类中。
- 容器: 负责创建对象、处理它们的生命周期,并将依赖项注入到需要它们的类中。
Autofac 是这些概念的优秀实现。
2. 核心概念
2.1 组件 (Components)
组件是 Autofac 管理的基本单元。你向容器"注册"组件,告诉它"当需要某个接口/类时,请使用这个具体的实现"。
- 可以注册的类型: 类、接口、委托、lambda 表达式等。
2.2 服务 (Services)
服务是组件如何被"识别"的方式。通常是一个接口(如 IEmailService
)或一个类(如 ConsoleLogger
)。注册时,你将一个服务映射到一个组件。
2.3 容器 (Container)
容器是所有组件注册的集合。它是整个依赖注入系统的核心。
2.4 生命周期 (Lifetime)
这是一个极其重要的概念,它决定了对象的实例何时被创建、共享以及何时被销毁。
- Instance Per Dependency: 每次请求都创建一个新实例。(类似 Transient)
- Single Instance: 整个应用程序生命周期内只创建一个实例(单例)。(类似 Singleton)
- Instance Per Lifetime Scope: 在一个特定的生命周期作用域内只创建一个实例。(类似 Scoped,在 Web 应用中非常常用,例如"每个 HTTP 请求一个实例")。
- Instance Per Matching Lifetime Scope: 更细粒度的作用域控制。
- Instance Per Request : (Web 专用) 每个 HTTP 请求一个实例。这是
Instance Per Lifetime Scope
在 Web 环境下的特化。
3. 基本使用步骤
步骤 1:安装 NuGet 包
在你的项目中,通过 NuGet 包管理器控制台或 UI 安装核心包:
bash
Install-Package Autofac
如果用于 ASP.NET Core 项目,还需要安装集成包:
bash
Install-Package Autofac.Extensions.DependencyInjection
步骤 2:创建容器构建器 (ContainerBuilder)
在应用程序启动时(如 Main
方法或 Startup.cs
),创建一个 ContainerBuilder
。
csharp
var builder = new ContainerBuilder();
步骤 3:注册组件
使用 ContainerBuilder
的各种方法来注册你的组件。
csharp
// 注册一个类型,将其自身作为服务(例如:注册 ConcreteLogger)
builder.RegisterType<ConsoleLogger>().As<ILogger>();
// 注册一个类型,并将其暴露为所有实现的接口(例如:注册 EmailService,它实现了 IEmailService 和 IDisposable)
builder.RegisterType<EmailService>().AsImplementedInterfaces();
// 注册一个特定的实例(单例)
var config = new Config { Host = "example.com" };
builder.RegisterInstance(config).As<IConfig>();
// 注册一个通过 lambda 表达式创建的实例
builder.Register(c => new ExpenseRepository("ConnectionString"))
.As<IRepository>();
// 注册一个泛型,例如:IRepository<T> 对应 Repository<T>
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>));
步骤 4:构建容器 (IContainer)
注册完所有组件后,构建一个不可变的容器。
csharp
IContainer container = builder.Build();
步骤 5:解析组件
从容器中请求(解析)你需要的服务。
csharp
// 直接从一个根容器解析(通常在应用程序根目录使用)
var logger = container.Resolve<ILogger>();
logger.Log("Hello, Autofac!");
// 重要:对于 Web 应用等,不应该直接从根容器解析,而应该从生命周期作用域解析。
步骤 6:管理生命周期和作用域 (重要!)
为了避免内存泄漏和确保正确的对象生命周期,必须正确使用作用域。
csharp
// 创建一個生命周期作用域
using (var scope = container.BeginLifetimeScope())
{
// 从作用域中解析服务
var service = scope.Resolve<IMyService>();
service.DoSomething();
// 当 using 块结束时,作用域及其内部创建的所有 IDisposable 对象会被释放。
}
// 在 ASP.NET Core 中,Autofac 集成库会自动为每个 HTTP 请求创建一个作用域。
// 你只需要在 Controller 或服务中通过构造函数注入即可,无需手动解析。
4. 与 ASP.NET Core 集成
现代 .NET 项目通常使用内置的 DI 容器,但 Autofac 提供了更多高级功能。集成步骤如下:
1. 修改 Program.cs
使用 Autofac 的 ConfigureContainer
方法来设置你的注册。
csharp
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 1. 告诉 ASP.NET Core 使用 Autofac 作为服务提供商
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// 2. 配置 Autofac 的容器
builder.Host.ConfigureContainer<ContainerBuilder>(autofacBuilder =>
{
// 在这里进行你的 Autofac 注册
autofacBuilder.RegisterModule(new MyApplicationModule());
// 或者直接注册
autofacBuilder.RegisterType<MyDependency>().As<IMyDependency>();
autofacBuilder.RegisterType<MyService>().As<IMyService>();
// 自动注册程序集中的所有类型
// autofacBuilder.RegisterAssemblyTypes(typeof(Program).Assembly)
// .Where(t => t.Name.EndsWith("Service"))
// .AsImplementedInterfaces();
});
// ... 其他服务注册(AddControllers, AddSwaggerGen 等)仍然使用内置容器
// builder.Services.AddControllers();
var app = builder.Build();
// ... 配置中间件管道
app.Run();
2. 使用模块 (Modules) 组织注册
为了保持 Program.cs
的整洁,推荐使用模块来组织复杂的注册逻辑。
csharp
// MyApplicationModule.cs
public class MyApplicationModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// 将相关的注册集中在这里
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
builder.RegisterType<EmailService>().As<IEmailService>().SingleInstance();
builder.RegisterType<SomeService>().As<ISomeService>();
// 注册所有 Controller (对于属性注入有时需要)
// var controllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(ControllerBase))).ToArray();
// builder.RegisterTypes(controllers).PropertiesAutowired();
}
}
3. 在 Controller 中使用
通过构造函数注入,这是最推荐的方式。
csharp
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly IWeatherService _weatherService;
private readonly ILogger<WeatherForecastController> _logger;
// 依赖项由 Autofac 自动注入
public WeatherForecastController(IWeatherService weatherService, ILogger<WeatherForecastController> logger)
{
_weatherService = weatherService;
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return _weatherService.GetForecasts();
}
}
5. 高级特性(简介)
-
属性注入 : 除了构造函数注入,Autofac 也支持通过属性注入依赖。但构造函数注入是首选。
csharpbuilder.RegisterType<MyService>().PropertiesAutowired();
-
自动装配 (Auto-wiring): Autofac 会自动解析构造函数参数所需的依赖,你无需手动指定。
-
模块化 : 如上所示,使用
Module
来组织注册,使代码更模块化。 -
拦截器 (AOP): Autofac 可以与 Castle DynamicProxy 集成,实现面向切面编程(AOP),用于日志、缓存、事务等横切关注点。
-
子容器/命名作用域: 支持更复杂的层次化容器结构。
总结
步骤 | 操作 | 说明 |
---|---|---|
1 | Install-Package Autofac |
安装核心库 |
2 | var builder = new ContainerBuilder(); |
创建构建器 |
3 | builder.RegisterType<T>().As<I>(); |
注册组件与服务 |
4 | var container = builder.Build(); |
构建不可变容器 |
5 | container.Resolve<I>() 或使用作用域 |
解析服务(谨慎使用根容器) |
(Web) | UseServiceProviderFactory |
在 ASP.NET Core 中集成 |
(组织) | 创建 Module 子类 |
将注册代码模块化 |
最佳实践建议:
- 优先使用构造函数注入。
- 谨慎使用属性注入,因为它会使依赖关系不明显。
- 理解并正确使用生命周期 ,尤其是
InstancePerLifetimeScope
,这是避免内存泄漏的关键。 - 在 Web 应用中,避免直接从根容器 (
IContainer
) 解析服务,始终使用生命周期作用域。 - 利用模块来保持启动代码的整洁。
希望这份指南能帮助你快速上手 Autofac!实践是学习的关键,尝试在一个小项目中应用它。