网站首页 > 技术文章 正文
简介
Autofac 是一个成熟的、功能丰富的 .NET 依赖注入(DI)容器。
相比于内置容器,它额外提供:模块化注册、装饰器(Decorator)、拦截器(Interceptor)、强o的属性/方法注入支持、基于约定的程序集扫描等特性。
核心组件
- ContainerBuilder:用于注册服务的构建器
- IContainer:服务容器,负责解析依赖
- ILifetimeScope:生命周期作用域,管理对象生命周期
- Module:模块化注册的基类
核心特性
灵活的服务注册
- 支持按类型、实例、工厂、委托等多种方式注册;
- 支持开放泛型(IRepository<T> → Repository<T>)、条件注册。
生命周期管理
- 同样有 Singleton、InstancePerDependency(每次)、InstancePerLifetimeScope(等同于 Scoped)、InstancePerMatchingLifetimeScope(自定义标签作用域)等多种模式。
模块化(Module)
- 通过继承 Module 将相关注册逻辑封装为可复用、可拆分的单元;
- 支持自动加载整个程序集中的 Module。
装饰器(Decorator)
- 可以很方便地为某个服务添加一层或多层“外衣”,例如日志、缓存等横切逻辑。
拦截器(Interceptor)
- 基于 Castle DynamicProxy,自动在方法调用前后执行 AOP 逻辑,如性能监控、事务管理等。
程序集扫描
- 支持按命名空间、接口、特性等约定,将多个实现一行注册。
基本使用
引入 NuGet
Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection # ASP.NET Core 集成
最简示例
using Autofac;
var builder = new ContainerBuilder();
// 1. 注册具体类型(默认使用 Transient 生命周期)
builder.RegisterType<OrderService>();
// 2. 注册接口与实现
builder.RegisterType<DbOrderRepository>().As<IOrderRepository>();
// 3. 注册单例
builder.RegisterType<AppConfig>().SingleInstance();
// 4. 注册工厂方法
builder.Register(c => new HttpClient()).InstancePerLifetimeScope();
builder.Register(c => {
var config = c.Resolve<IConfiguration>();
return new MyService(config.GetConnectionString("Default"));
}).As<IMyService>();
// 5. 注册已存在的实例
var logger = new NLogLogger();
builder.RegisterInstance(logger).As<ILogger>();
// 6. 注册开放泛型类型
builder.RegisterGeneric(typeof(MyRepository<>)).As(typeof(IRepository<>));
// 构建容器
var container = builder.Build();
// 从容器中解析服务
using (var scope = container.BeginLifetimeScope()) {
var service = scope.Resolve<OrderService>();
}
服务暴露 (Exposing Services)
As<T>(): 将组件暴露为特定服务类型 T (通常是接口)
builder.RegisterType<EmailSender>().As<IEmailSender>();
As<TService1, TService2>(): 将组件暴露为多个服务类型
builder.RegisterType<FileLogger>().As<ILogger, IFileLogger>();
AsImplementedInterfaces(): 将组件暴露为其实现的所有公共接口
builder.RegisterType<CustomerRepository>().AsImplementedInterfaces();
// 等同于 .As<ICustomerRepository, IRepository<Customer>, ...>()
AsSelf(): 将组件暴露为其自身类型。通常与其他.As()一起使用
builder.RegisterType<MySpecialService>().AsSelf().As<ISpecialService>();
生命周期(Scope)管理
生命周期 | 对应 Autofac 方法 | 场景 |
瞬时 / 每次依赖 | .InstancePerDependency() (默认) | 无状态、轻量对象 |
单例 / 容器范围 | .SingleInstance() | 线程安全、全局共享 |
每个生命周期作用域 | .InstancePerLifetimeScope() | 类似 ASP.NET Core 的 Scoped 模式 |
每个 HTTP 请求内单例 | .InstancePerRequest() | 仅 ASP.NET Core 集成支持 |
自定义标记作用域 | .InstancePerMatchingLifetimeScope("tag") | 某些特定操作需独立作用域 |
builder.RegisterType<CacheService>()
.As<ICacheService>()
.SingleInstance();
builder.RegisterType<DbContext>()
.AsSelf()
.InstancePerLifetimeScope();
var tagScope = container.BeginLifetimeScope("unitOfWork");
var ctx = tagScope.Resolve<DbContext>(); // 属于 "unitOfWork" 作用域
高级特性
属性注入
public class MyService {
[Inject] // 注入属性
public ILogger Logger { get; set; } // 自动注入的属性
}
// 注册时启用属性注入
builder.RegisterType<MyService>()
.ProjertiesAutowired();
手动解析
public class MyService
{
private readonly IComponentContext _context;
public MyService(IComponentContext context)
{
_context = context;
}
public void DoWork()
{
var userService = _context.Resolve<IUserService>();
// 使用 userService
}
}
命名与键控服务
// 注册多个实现,使用命名区分
builder.RegisterType<SqlDbContext>().Named<DbContext>("sql");
builder.RegisterType<MongoDbContext>().Named<DbContext>("mongo");
// 解析时指定名称
var sqlContext = scope.ResolveNamed<DbContext>("sql");
集合解析
自动解析所有实现某一接口的服务
container.RegisterType<UserService1>().As<IUserService>();
container.RegisterType<UserService2>().As<IUserService>();
// 解析所有实现
public class MultiService
{
private readonly IEnumerable<IUserService> _services;
public MultiService(IEnumerable<IUserService> services)
{
_services = services;
}
}
作用域管理
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<IUserService>();
// 使用 service
}
高级作用域控制
- 嵌套作用域
using (var parentScope = container.BeginLifetimeScope())
{
var serviceA = parentScope.Resolve<ServiceA>();
using (var childScope = parentScope.BeginLifetimeScope())
{
var serviceB = childScope.Resolve<ServiceB>(); // 可访问父作用域实例
}
}
- 带标签作用域 (Tagged Scopes)
// 注册时标记作用域
builder.RegisterType<EmailSender>()
.As<IEmailSender>()
.InstancePerMatchingLifetimeScope("transaction");
// 使用标签创建作用域
using (var transactionScope = container.BeginLifetimeScope("transaction"))
{
var emailSender = transactionScope.Resolve<IEmailSender>(); // 事务内共享实例
}
模块化注册
当项目庞大或有多个子系统时,将注册逻辑封装在 Module 中,便于维护与复用。
// 定义模块
public class DataModule : Module {
protected override void Load(ContainerBuilder builder) {
builder.RegisterType<DbConnection>().As<IDbConnection>();
builder.RegisterType<OrderRepository>().As<IOrderRepository>();
}
}
// 注册模块
builder.RegisterModule<DataModule>();
public class RepositoryModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// 自动扫描程序集内的 IRepository<> 实现
builder.RegisterAssemblyTypes(typeof(RepositoryModule).Assembly)
.AsClosedTypesOf(typeof(IRepository<>))
.InstancePerLifetimeScope();
}
}
// 在主程序里加载
var builder = new ContainerBuilder();
builder.RegisterModule<RepositoryModule>();
builder.RegisterModule(new SettingsModule(settings));
装饰器(Decorator)
给已有服务动态“套”上日志、缓存等功能,不需改动原实现。
// 原始服务
builder.RegisterType<OrderService>()
.As<IOrderService>();
// 装饰器:构造参数 inner 实例即被装饰的服务
builder.RegisterDecorator<LoggingOrderService, IOrderService>();
- 等同于:当解析 IOrderService 时,先创建 OrderService,再将其传给 LoggingOrderService 构造器。
AOP 拦截与动态代理
基于 Castle DynamicProxy,为接口或虚方法生成代理,在调用前后执行拦截逻辑。
引入包
Install-Package Autofac.Extras.DynamicProxy
Install-Package Castle.Core
// 定义拦截器
public class LoggingInterceptor : IInterceptor {
public void Intercept(IInvocation invocation) {
Console.WriteLine(#34;调用方法: {invocation.Method.Name}");
invocation.Proceed(); // 执行原始方法
Console.WriteLine(#34;方法返回: {invocation.ReturnValue}");
}
}
// 注册带拦截器的服务
builder.RegisterType<OrderService>()
.As<IOrderService>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(LoggingInterceptor));
builder.RegisterType<LoggingInterceptor>();
程序集扫描与约定注册
根据命名、接口或特性,批量注册类型:
// 按接口后缀约定:所有以 "Service" 结尾的类,注册为它们所实现的接口
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
条件注册
builder.RegisterType<SqlRepository>()
.As<IRepository>()
.When(c => c.Parameters.Any(p => p.Name == "useSql" && (bool)p.Value));
装配时验证
// 验证所有注册的服务可被解析
container.AssertConfigurationIsValid();
循环依赖解决
延迟注入
builder.Register(c => new ServiceA(c.Resolve<Lazy<IServiceB>>()));
builder.Register(c => new ServiceA(c.Resolve<Func<IServiceB>>()))
.As<IServiceA>();
builder.Register(c => new ServiceB(c.Resolve<IServiceA>()))
.As<IServiceB>();
builder.RegisterType<ServiceA>().As<IService>()
.OnlyIf(reg => Environment.IsDevelopment);
混合使用内置 DI 和 Autofac
builder.Services.AddScoped<IOtherService, OtherService>(); // 内置 DI
builder.Host.ConfigureContainer<ContainerBuilder>(container =>
{
container.RegisterType<UserService>().As<IUserService>();
});
与 ASP.NET Core 集成
在 Program.cs 中替换容器
// Program.cs
using Autofac.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// 使用 Autofac 替换默认 DI 容器
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
// 配置 Autofac 服务
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder => {
containerBuilder.RegisterType<CustomService>().As<IService>();
containerBuilder.RegisterModule<MyModule>();
});
var app = builder.Build();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule<RepositoryModule>();
//… 其他注册
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
在控制台应用中使用
var builder = new ContainerBuilder();
builder.RegisterModule<ApplicationModule>();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope()) {
var service = scope.Resolve<IMyService>();
service.Run();
}
最佳实践与常见问题
避免服务定位器反模式
// 反模式:直接从容器解析服务
var service = container.Resolve<IMyService>();
// 正确做法:通过构造函数注入
public class MyConsumer {
private readonly IMyService _service;
public MyConsumer(IMyService service) { _service = service; }
}
猜你喜欢
- 2025-07-24 Channels: C# 实现高效的线程间通信
- 2025-07-24 一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试
- 2025-07-24 C# 获取Windows的系统信息(c# 获取本机的ip地址)
- 2025-07-24 C# 读取本地网络配置信息(c# 读取配置文件的方法)
- 2025-07-24 MODBUS协议在C#中的应用案例(c#modbus 程序)
- 2025-07-24 C#接口(c接口镜头)
- 2025-07-24 AngleSharp :在 C# 中轻松解析和操作 HTML/XML 文档
- 2025-07-24 C#中的9个“黑魔法”与“骚操作”
- 2025-07-24 C#.NET Ninject 详解(c#.net framework)
- 2025-07-24 C#.NET HttpClient 使用教程(c#开启http服务)
- 1517℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 594℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 521℃MySQL service启动脚本浅析(r12笔记第59天)
- 489℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 489℃启用MySQL查询缓存(mysql8.0查询缓存)
- 477℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 456℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 454℃MySQL server PID file could not be found!失败
- 最近发表
-
- PS所有滤镜的说明(六)(ps滤镜详解)
- 5款小白也能用的在线图片编辑器!电商效率飙升就靠它!
- Java变量(java变量有什么作用)
- Java面试常见问题:Java注解(java中的面试题)
- Java编程入门第一课:HelloWorld(java编程从入门到实践)
- Java基础教程:Java继承概述(java里继承的概述)
- java基础之——访问修饰符(private/default/protected/public)
- 如何规划一个合理的JAVA项目工程结构
- 将机器指令翻译成 JavaScript -- 终极目标
- Web 服务器基准测试:Go vs. Node.js vs. Nim vs. Bun
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)