
C# Autofac 新手指南:从零理解依赖注入与组件装配
文章目录
- C# Autofac 新手指南:从零理解依赖注入与组件装配
-
- 1 什么是依赖注入与 Autofac
-
- 1.1 概念讲解:搞懂三个核心术语
- 1.2 主流 IoC 容器对比与应用场景
- 1.3 C# 与依赖注入的发展历程
- 2 Autofac/DI 代码与传统代码的对比
-
- 2.1 代码特点对比
-
- 传统代码(硬编码直接依赖)
- Autofac / DI 代码(解耦与面向接口)
- 2.2 Autofac 代码风格与设计优势
- 2.3 帮助理解依赖注入与 Autofac 的方法
- 3 使用 Autofac 的意义与架构定位
-
- 3.1 适用场景与不适用场景
-
- 适用场景
- 不适用场景
- 3.2 Autofac 在 DDD 系统架构中的位置
- 3.3 实际案例演示:解耦前后对比
-
- 场景:系统升级,需要将订单储存方式从 SQL Server 升级为 Redis 缓存。
- 4 手把手体验 Autofac
-
- 4.1 第一行 Autofac 代码( Console 控制台极简体验)
- 4.2 语法与核心 API 详解
-
- 4.2.1 组件注册方式 (Registration)
-
- 1. 类型注册 (RegisterType)
- 2. 程序集扫描注册 (RegisterAssemblyTypes) —— **Autofac 的杀手级特性**
- 3. 模块化注册 (Module)
- 4.2.2 生命周期管理 (Lifetime Management)
-
- 代码应用示例:
- 5 总结
1 什么是依赖注入与 Autofac
1.1 概念讲解:搞懂三个核心术语
在进入 Autofac 之前,很多初学者容易被 IoC、DIP 和 DI 这三个英文缩写绕晕。用现实生活中的例子可以轻松理清它们的关系:

-
DIP(Dependency Inversion Principle,依赖倒置原则):
-
含义: 一项设计原则。高层模块不应该依赖底层模块,两者都应该依赖于抽象(接口或抽象类);抽象不应该依赖细节,细节应该依赖抽象。
-
生活比喻: 墙上的插座(接口)不关心接进来的是电风扇还是吹风机(具体实现),只要符合国家插头标准,就能供电。
-
IoC(Inversion of Control,控制反转):
-
含义: 一种设计思想。把对象的创建、组装和生命周期控制权,从代码本身“反转”交给外部容器或框架。
-
生活比喻: 以前你想吃汉堡,必须自己准备面粉、牛肉并亲自下厨(主动创建依赖);现在你去麦当劳,点单后由厨师做出汉堡递给你(控制权反转)。
-
DI(Dependency Injection,依赖注入):
-
含义: IoC 思想的具体实现技术。在运行期间,由外部容器将被依赖的对象通过构造函数、属性或方法“注入”给使用它的对象。
-
Autofac 的角色: Autofac 就是一个功能极其强大、高性能的 .NET IoC 容器框架,负责帮你在应用中自动化完成依赖注入的繁琐工作。
1.2 主流 IoC 容器对比与应用场景
在 .NET 生态中,存在多种 IoC 容器。了解它们的差异有助于在项目中做出正确的技术选型:
| Microsoft.Extensions.DependencyInjection (原生) | 零额外包引入,极轻量,开箱即用 | 功能较为基础,缺乏自动程序集扫描、属性注入和复杂的生命周期控制 | 小型项目、标准微服务、逻辑简单的 API 服务 |
| Autofac | 功能极为全面,支持程序集批量注册、模块化配置(Module)、属性注入、拦截器(AOP) | 相比原生注入有少量学习成本 | 中大型项目、复杂企业级系统、采用 DDD 架构的应用 |
| Castle Windsor | 历史悠久,扩展性极强 | 相对偏重,近几年更新频率较低 | 维护较早期的传统企业级 .NET Framework 项目 |
1.3 C# 与依赖注入的发展历程

2 Autofac/DI 代码与传统代码的对比
2.1 代码特点对比
假设需要实现一个订单结算服务,它依赖于数据库读取组件(OrderRepository)。

传统代码(硬编码直接依赖)
// 数据库读取类
public class OrderRepository
{
public string GetOrderData(int orderId) => $"Order #{orderId} data from SQL Server";
}
// 订单服务类
public class OrderService
{
private readonly OrderRepository _repository;
public OrderService()
{
// 严重问题:OrderService 强绑定了具体的 OrderRepository
// 如果想换成 MongoDbRepository,必须修改此类源代码
_repository = new OrderRepository();
}
public void ProcessOrder(int orderId)
{
var data = _repository.GetOrderData(orderId);
Console.WriteLine($"Processing: {data}");
}
}
Autofac / DI 代码(解耦与面向接口)
// 1. 定义抽象接口
public interface IOrderRepository
{
string GetOrderData(int orderId);
}
// 2. 实现接口
public class SqlOrderRepository : IOrderRepository
{
public string GetOrderData(int orderId) => $"Order #{orderId} data from SQL Server";
}
// 3. 订单服务依赖抽象接口,而非具体实现
public class OrderService
{
private readonly IOrderRepository _repository;
// 构造函数注入:由 Autofac 在运行时自动传人具体的实现对象
public OrderService(IOrderRepository repository)
{
_repository = repository;
}
public void ProcessOrder(int orderId)
{
var data = _repository.GetOrderData(orderId);
Console.WriteLine($"Processing: {data}");
}
}
2.2 Autofac 代码风格与设计优势
2.3 帮助理解依赖注入与 Autofac 的方法
将构建软件系统想象成 “台式电脑组装”:
- 传统代码: 就像主板上直接把 CPU、内存条焊死。虽然能用,但一旦内存不够用,整台电脑只能报废。
- 面向接口(DIP): 主板定义了 DDR5 内存插槽标准,无论谁生产的内存条,符合标准就能插上。
- Autofac(装配工厂): 你是客户,写了一份配置单(注册组件),Autofac 是自动化装配车间。它看到你需要一台电脑,就会去仓库拿符合接口标准的内存条、CPU 和显卡,组装好后直接整机交付给你使用。
3 使用 Autofac 的意义与架构定位
3.1 适用场景与不适用场景

适用场景
- 大型/多模块系统: 项目中有成百上千个 Service 和 Repository,需要通过程序集自动批量注册。
- 需要 AOP 动态代理: 需要无侵入地在方法执行前后加上日志记录、性能统计、事务控制或缓存逻辑。
- 复杂领域驱动设计(DDD): 层次清晰、依赖关系错综复杂,需要灵活的生命周期隔离和模块装配。
不适用场景
- 一次性命令行小工具: 代码总量只有几百行,不需要后期维护,引入 DI 框架反而徒增代码复杂度。
- 性能极度敏感的核心计算算法内部: 如果某个极其底层的紧密循环每秒需要执行几百万次,通过 DI 容器动态解析会带来毫秒级/微秒级的额外反射耗时,此时直接实例化或静态方法更为适宜。
3.2 Autofac 在 DDD 系统架构中的位置
在标准的 DDD(领域驱动设计)分层架构中,底层基础设施层(Infrastructure)实现了领域层(Domain)和应用层(Application)定义的接口。
为了避免上层代码直接引用基础设施层的具体类,Autofac 存在于系统的“组合根”(Composition Root)中(通常即最外层的程序入口点,如 API 层的 Startup.cs 或 Program.cs)。
#mermaid-svg-97rOkttkaj1mCQbE{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-97rOkttkaj1mCQbE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-97rOkttkaj1mCQbE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-97rOkttkaj1mCQbE .error-icon{fill:#552222;}#mermaid-svg-97rOkttkaj1mCQbE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-97rOkttkaj1mCQbE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-97rOkttkaj1mCQbE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-97rOkttkaj1mCQbE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-97rOkttkaj1mCQbE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-97rOkttkaj1mCQbE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-97rOkttkaj1mCQbE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-97rOkttkaj1mCQbE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-97rOkttkaj1mCQbE .marker.cross{stroke:#333333;}#mermaid-svg-97rOkttkaj1mCQbE svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-97rOkttkaj1mCQbE p{margin:0;}#mermaid-svg-97rOkttkaj1mCQbE .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-97rOkttkaj1mCQbE .cluster-label text{fill:#333;}#mermaid-svg-97rOkttkaj1mCQbE .cluster-label span{color:#333;}#mermaid-svg-97rOkttkaj1mCQbE .cluster-label span p{background-color:transparent;}#mermaid-svg-97rOkttkaj1mCQbE .label text,#mermaid-svg-97rOkttkaj1mCQbE span{fill:#333;color:#333;}#mermaid-svg-97rOkttkaj1mCQbE .node rect,#mermaid-svg-97rOkttkaj1mCQbE .node circle,#mermaid-svg-97rOkttkaj1mCQbE .node ellipse,#mermaid-svg-97rOkttkaj1mCQbE .node polygon,#mermaid-svg-97rOkttkaj1mCQbE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-97rOkttkaj1mCQbE .rough-node .label text,#mermaid-svg-97rOkttkaj1mCQbE .node .label text,#mermaid-svg-97rOkttkaj1mCQbE .image-shape .label,#mermaid-svg-97rOkttkaj1mCQbE .icon-shape .label{text-anchor:middle;}#mermaid-svg-97rOkttkaj1mCQbE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-97rOkttkaj1mCQbE .rough-node .label,#mermaid-svg-97rOkttkaj1mCQbE .node .label,#mermaid-svg-97rOkttkaj1mCQbE .image-shape .label,#mermaid-svg-97rOkttkaj1mCQbE .icon-shape .label{text-align:center;}#mermaid-svg-97rOkttkaj1mCQbE .node.clickable{cursor:pointer;}#mermaid-svg-97rOkttkaj1mCQbE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-97rOkttkaj1mCQbE .arrowheadPath{fill:#333333;}#mermaid-svg-97rOkttkaj1mCQbE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-97rOkttkaj1mCQbE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-97rOkttkaj1mCQbE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-97rOkttkaj1mCQbE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-97rOkttkaj1mCQbE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-97rOkttkaj1mCQbE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-97rOkttkaj1mCQbE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-97rOkttkaj1mCQbE .cluster text{fill:#333;}#mermaid-svg-97rOkttkaj1mCQbE .cluster span{color:#333;}#mermaid-svg-97rOkttkaj1mCQbE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-97rOkttkaj1mCQbE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-97rOkttkaj1mCQbE rect.text{fill:none;stroke-width:0;}#mermaid-svg-97rOkttkaj1mCQbE .icon-shape,#mermaid-svg-97rOkttkaj1mCQbE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-97rOkttkaj1mCQbE .icon-shape p,#mermaid-svg-97rOkttkaj1mCQbE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-97rOkttkaj1mCQbE .icon-shape .label rect,#mermaid-svg-97rOkttkaj1mCQbE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-97rOkttkaj1mCQbE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-97rOkttkaj1mCQbE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-97rOkttkaj1mCQbE :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
组合根 (Composition Root) – 程序入口点
基础设施层 (Infrastructure)
领域层 (Domain)
应用层 (Application)
UI / API 层 (Presentation)
实现
实现
1. 自动扫描绑定
1. 自动扫描绑定
2. 解析并注入到
2. 解析并注入到
Controllers / Endpoints
App Services / Command Handlers
Domain Services
IRepository / IExternalService (抽象接口)
EfOrderRepository
RabbitMqPublisher
Autofac ContainerBuilder(组装与装配中心)
关键点: Autofac 是连接抽象接口和具体实现的“胶水”,它站在最外层统一感知所有的具体类型,并将具体实现注入到上层架构中。
3.3 实际案例演示:解耦前后对比
场景:系统升级,需要将订单储存方式从 SQL Server 升级为 Redis 缓存。
- 没有 Autofac: 需要去修改 OrderService 中的 new SqlOrderRepository() 逻辑;如果有 50 个 Service 都用到了它,就需要修改 50 处代码。
- 使用 Autofac: OrderService 的代码一行都不用变,只需要修改 Autofac 的集中注册配置:
// 原注册:绑定为 SQL 实现
// builder.RegisterType<SqlOrderRepository>().As<IOrderRepository>();
// 现注册:改绑为 Redis 实现
builder.RegisterType<RedisOrderRepository>().As<IOrderRepository>();
整个系统的全部业务代码自动切换为最新的存储逻辑,改动范围被严格限定在系统配置入口。
4 手把手体验 Autofac
4.1 第一行 Autofac 代码( Console 控制台极简体验)
可以通过 NuGet 安装包:Install-Package Autofac。
using Autofac;
using System;
namespace AutofacDemo
{
// 1. 定义接口和类
public interface IGreetService
{
void SayHello(string name);
}
public class ConsoleGreetService : IGreetService
{
public void SayHello(string name) => Console.WriteLine($"Hello, {name}!");
}
class Program
{
static void Main(string[] args)
{
// 2. 创建容器构建器 (ContainerBuilder)
var builder = new ContainerBuilder();
// 3. 注册组件:将 ConsoleGreetService 注册为 IGreetService 的实现
builder.RegisterType<ConsoleGreetService>().As<IGreetService>();
// 4. 构建容器 (IContainer)
using (var container = builder.Build())
{
// 5. 从容器中解析组件 (Resolve)
var greetService = container.Resolve<IGreetService>();
// 6. 使用组件
greetService.SayHello("Autofac 新手");
} // 离开 using 作用域,容器及自动管理的资源会被统一释放
}
}
}
4.2 语法与核心 API 详解
4.2.1 组件注册方式 (Registration)
Autofac 提供了极具弹性的注册方式,最常用的有以下三种: 
1. 类型注册 (RegisterType)
最基础的针对单个类的注册。
builder.RegisterType<SqlOrderRepository>().As<IOrderRepository>();
2. 程序集扫描注册 (RegisterAssemblyTypes) —— Autofac 的杀手级特性
无需逐个手动注册,自动扫描指定程序集(Assembly)下所有的类,按照规则批量注册。
var repositoryAssembly = System.Reflection.Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(repositoryAssembly)
.Where(t => t.Name.EndsWith("Repository")) // 类名以 Repository 结尾
.AsImplementedInterfaces(); // 自动绑定它实现的所有接口
3. 模块化注册 (Module)
将逻辑相近的组件配置打包封装到一个单独的类中。
// 定义模块
public class DatabaseModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<SqlOrderRepository>().As<IOrderRepository>();
builder.RegisterType<DbContext>().InstancePerLifetimeScope();
}
}
// 主入口中直接加载模块
builder.RegisterModule<DatabaseModule>();
4.2.2 生命周期管理 (Lifetime Management)
当向 Autofac 请求某个对象时,Autofac 是重新 new 一个,还是复用已有的?这就是生命周期决定的。
| InstancePerDependency() | 瞬态 (Transient) | 默认策略。每次调用 Resolve 或注入时,都创建一个全新的实例 | 无状态的轻量级 Service、工具类 |
| SingleInstance() | 单例 (Singleton) | 整个应用程序生命周期内只创建一次实例,后续解析全部复用该对象 | 全局配置类、内存缓存管理器 |
| InstancePerLifetimeScope() | 作用域 (Scoped) | 在同一个 LifetimeScope(如一次 HTTP 请求)内共享同一个实例 | 数据库上下文(如 Entity Framework DbContext) |
代码应用示例:
// 单例模式:全局唯一
builder.RegisterType<CacheManager>().As<ICacheManager>().SingleInstance();
// Scoped 模式:同一作用域/HTTP请求内唯一
builder.RegisterType<MyDbContext>().InstancePerLifetimeScope();
5 总结
学习 Autofac 的核心价值不在于记忆 API,而在于理解并践行“解耦”的设计哲学:
迈出第一步后,你可以在下一个 ASP.NET Core 项目中,尝试使用 Autofac 替换原生的 DI 容器,体会模块化和程序集扫描带来的高效开发体验。
网硕互联帮助中心






评论前必须登录!
注册