如何在ASP.NET 8.0+ 中使用依赖注入框架Autofac

前言

为什么需要Autofac

.NET 提供了其轻量级的内置框架Microsoft.Extention.DependencyInjection,用于实现依赖注入(DI)、控制反转(IoC)。但是这个框架的依赖注册(Register)比较繁琐,只能单个依赖地注入。Autofac是一个第三方的.NET Core 框架,该框架的一大优点就是可以结合反射,对一个程序集(Assembly)内的实现了接口的类进行分别的依赖注册(官网首页的Register Compenents部分有示例代码)。

Autofac 官网

为什么需要这篇文章

然而,国内社区中 .NET 相关的资料不太多,也比较落后。而且,Autofac 提供的中文文档的最新版本是4.0版本,落后于最新版本是7.0版本的英文文档。此外,英文文档似乎也没有更新,至少其中的集成应用中的ASP.NET Core 的介绍没有使用最新的语法。根据文档,我找到了Autofac 在Github 上的示例代码,结果我需要的部分都是3年前的版本。

这三年ASP.NET Core 做了许多的改变。C# 9.0(大约3年前)开始引入的顶级语句在后续的ASP.NET Core 中被应用,Startup.cs 文件不再需要,Program.cs 也有了很多的变化。3年前的实例代码中启动应用的方法,和现如今ASP.NET Core 提供的模板差别很大,无法用于学习。

入门

我认为官方文档中创建ContainerBuilder对象、然后用其进行注册的方法在现今版本的ASP.NET Core 中是不可行的,因为我能看到的实例代码中,这一步都是在Startup.cs文件中的某一个方法内。而且,ASP.NET Core 似乎做了很多的更改,导致网上的许多过时的指导中需要用的方法、对象都不可用。

我在StackOverFlow 上看到了一篇问答,最后找到了合适的使用方法。原文链接:https://stackoverflow.com/questions/69754985/adding-autofac-to-net-core-6-0-using-the-new-single-file-template 。根据这篇这篇问答以及我的亲身实验,我总结出了以下指南(只是介绍下流程,具体的流程下的原理之类的我也不清楚)

简述流程

using Autrofac;
using Autofac.Extentions.DependencyInjection;

var builder = new WebApplication(args);

// 重点
// 将Autofac 的依赖容器提供给WebApplication,
// 这样,通过Autofac 注册的组件就能够被注入
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

var app = builder.Build();
app.Run();

组件注册(Registering Components)

和过时的官方文档一样,注册组件的方法也是要通过ContainerBuilder对象进行,但是我们不需要(或者说不能)去手动创建这个对象,而是交由AutofacServiceProviderFactory类。首先看一下这个类的一个构造函数

/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceProviderFactory"/> class.
/// </summary>
/// <param name="configurationAction">Action on a <see cref="ContainerBuilder"/> that adds component registrations to the container..</param>
public AutofacServiceProviderFactory(Action<ContainerBuilder>? configurationAction = null)

可以看到,这个构造函数接受一个类型为Action<ContainerBuilder>的委托,注释指出该委托用于向Autofac 依赖容器中添加组件。也就是说,我们要把文档中使用ContainerBuilder对象进行组件注册的代码写在一个委托中,再将这个委托作为AutofacServiceProviderFactory的构造函数的参数传入。

这样也有好处,我会在Program.cs文件中定一个签名与委托匹配的方法,在其中进行必要的依赖注入,也有利于增强顶级语句的可读性。

需要注意的是,据我观察,同时使用Autofac 以及内置的依赖注入进行注册都是有效的。也就是说,以上相当于把通过Autofac 注入的组件并入内置依赖注入框架的容器中(不太严谨地说)。个人感觉像DbContext、控制器的注册,还是用内置依赖注入好。我使用Autfofac,主要也是为了补充内置框架的不足。

依赖注入

官方文档指出,可以使用隐式的依赖注入,我也有验证过,构造器注入的方式确实是隐式有效的。具体详见官方文档,目测没有太多改变。Resolving Services — Autofac 7.0.0 documentation

我的示例

using System.Reflection;
using Autofac;
using Autofac.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// controllers
builder.Services.AddControllers();

// Redis
builder.Services.AddSingleton<IDatabase>(_ => ConnectionMultiplexer
    .Connect(builder.Configuration.GetConnectionString("Redis") ?? throw new Exception("Connection string 'Redis' not found."))
    .GetDatabase()
);

// DbContext
builder.Services.AddDbContext<DiggingSoilContext>(options =>
    options.UseMySQL(builder.Configuration.GetConnectionString("MySql") ?? throw new Exception("Connection string 'MySql' not found."))
);

// Use Autofac
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory(DependencyHelper));
var app = builder.Build();
app.Run();

void AutofacContainerBuilderConfiguration(ContainerBuilder containerBuilder)
{
    // Services
    containerBuilder.RegisterAssemblyTypes(Assembly.Load("MyProject.Services"))
        .Where(t => t.IsClass && t.Name.EndsWith("Service"))
        .AsImplementedInterfaces()
        .SingleInstance();

    // Repos
    containerBuilder.RegisterAssemblyTypes(Assembly.Load("MyProject.Dal"))
        .Where(t => t.IsClass && t.Name.EndsWith("Repo"))
        .AsImplementedInterfaces()
        .SingleInstance();
}

如有错误,欢迎指正

  • 37
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值