查漏补缺之Autofac

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 也支持通过属性注入依赖。但构造函数注入是首选。

    csharp 复制代码
    builder.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 子类 将注册代码模块化

最佳实践建议

  1. 优先使用构造函数注入
  2. 谨慎使用属性注入,因为它会使依赖关系不明显。
  3. 理解并正确使用生命周期 ,尤其是 InstancePerLifetimeScope,这是避免内存泄漏的关键。
  4. 在 Web 应用中,避免直接从根容器 (IContainer) 解析服务,始终使用生命周期作用域。
  5. 利用模块来保持启动代码的整洁。

希望这份指南能帮助你快速上手 Autofac!实践是学习的关键,尝试在一个小项目中应用它。

相关推荐
小码编匠4 小时前
手把手教会设计 WinForm 高DPI兼容程序,告别字体模糊与控件乱飞(.NET 4.6.1/.NET 6.0)
后端·c#·.net
钩鸿踏月5 小时前
复盘一个诡异的Bug之FileNotFoundException
c#·bug·.net
INSO6 小时前
查漏补缺之Autofac生命周期
c#
小乖兽技术7 小时前
C#与C++交互开发系列(三十):C#非托管内存分配大比拼,哪种方式才是真正的性能王者?
c++·c#·交互
CodeCraft Studio7 小时前
PPT处理控件Aspose.Slides教程:使用 C# 编程将 PPTX 转换为 XML
xml·c#·powerpoint·aspose·ppt转xml·ppt文档开发
用户7227868123448 小时前
使用c#强大的SourceGenerator现对象的深克隆
c#
好望角雾眠8 小时前
第二阶段WinForm-11:自定义控件
笔记·c#·#笔记·#自定义控件
wuk9989 小时前
C#开发OPC UA客户端
开发语言·c#
CodeCraft Studio16 小时前
PPT处理控件Aspose.Slides教程:在 C# 中将 PPTX 转换为 Markdown
开发语言·c#·powerpoint·markdown·ppt·aspose·ai大模型