练习 - 通过 RabbitMQ 在微服务之间发送消息
RabbitMQ 是一个可靠的消息中转站,提供灵活的消息交换和队列。 若要在 .NET Aspire 项目中通过 RabbitMQ 发送和接收消息,必须添加一个 RabbitMQ 容器,然后创建从一个微服务发送消息并在另一个微服务中接收消息的代码。
在本练习中,你将从 Catalog.API 项目向队列发送消息。 你将添加一个新的后台服务项目,用于从队列接收这些消息并将其发送到控制台日志进行显示。
安装先决条件
.NET Aspire 的先决条件包括:
- .NET 8
- Visual Studio 2022 预览版
- Docker Desktop 或 Podman
- Visual Studio 中的 .NET Aspire 工作负载
如果已安装这些包,则可以跳过此步骤并直接开始使用 RabbitMQ。
安装 .NET 8
单击此 .NET 8 链接,然后根据操作系统选择正确的安装程序。 例如,如果使用的是 Windows 11 和新式处理器,请选择适用于 Windows 的 x64 .NET 8 SDK。
下载完成后,运行安装程序并按照说明操作。 在终端窗口中,运行以下命令以验证安装是否成功:
dotnet --version
应会看到所安装的 .NET SDK 版本号。 例如:
8.0.300-preview.24203.14
安装 Visual Studio 2022 预览版
单击此 Visual Studio 2022 预览版链接,然后选择“下载预览版”。 下载完成后,运行安装程序并按照说明操作。
安装 Docker Desktop
单击此 Docker Desktop 链接,然后根据操作系统选择正确的安装程序。 下载完成后,运行安装程序并按照说明操作。 为了获得最佳性能和兼容性,请使用 WSL 2 后端。
打开 Docker Desktop 应用程序并接受服务协议。
在 Visual Studio 中安装 .NET Aspire 工作负载
使用 .NET CLI 安装 .NET Aspire 工作负载:
打开终端。
使用以下命令更新 .NET 工作负载:
dotnet workload update
应会看到一条消息,指出工作负载已成功更新。
No workloads installed for this feature band. To update workloads installed with earlier SDK versions, include the --from-previous-sdk option. Updated advertising manifest microsoft.net.sdk.ios. Updated advertising manifest microsoft.net.workload.mono.toolchain.net6. Updated advertising manifest microsoft.net.sdk.android. Updated advertising manifest microsoft.net.workload.emscripten.net7. Updated advertising manifest microsoft.net.workload.emscripten.net6. Updated advertising manifest microsoft.net.sdk.macos. Updated advertising manifest microsoft.net.workload.emscripten.current. Updated advertising manifest microsoft.net.workload.mono.toolchain.current. Updated advertising manifest microsoft.net.sdk.maui. Updated advertising manifest microsoft.net.workload.mono.toolchain.net7. Updated advertising manifest microsoft.net.sdk.maccatalyst. Updated advertising manifest microsoft.net.sdk.tvos. Updated advertising manifest microsoft.net.sdk.aspire. No workloads installed for this feature band. To update workloads installed with earlier SDK versions, include the --from-previous-sdk option. Successfully updated workload(s): .
使用以下命令安装 .NET Aspire 工作负载:
dotnet workload install aspire
你应会看到一条消息,指出已安装 Aspire 工作负载。
Installing Aspire.Hosting.Sdk.Msi.x64 ...... Done Installing Aspire.ProjectTemplates.Msi.x64 ..... Done Installing Aspire.Hosting.Orchestration.win-x64.Msi.x64 ............. Done Installing Aspire.Hosting.Msi.x64 ..... Done Installing Aspire.Dashboard.Sdk.win-x64.Msi.x64 ....... Done Successfully installed workload(s) aspire.
使用以下命令验证是否安装了 .NET Aspire 工作负载:
dotnet workload list
应会看到 .NET Aspire 工作负载的详细信息。
Installed Workload Id Manifest Version Installation Source --------------------------------------------------------------------------------------------- aspire 8.0.0/8.0.100 SDK 8.0.300-preview.24203, VS 17.10.34902.84 Use `dotnet workload search` to find additional workloads to install.
克隆项目
让我们使用 git
来获取一个尚未使用消息中转站的示例应用:
在命令行中,浏览到你选择的、可在其中处理代码的文件夹。
执行以下命令克隆示例应用程序:
git clone -b aspire-rabbitmq https://github.com/MicrosoftDocs/mslearn-aspire-starter
创建 RabbitMQ 容器
首先,我们将 RabbitMQ 添加到应用主机项目。 当我们启动解决方案时,.NET Aspire 会向应用程序添加一个 RabbitMQ 容器并将引用传递给使用它的项目:
启动 Visual Studio 并选择“打开项目或解决方案”。
导航到项目克隆到的文件夹。
双击“start”文件夹,选择“eShop.rabbitmq.sln”解决方案,然后选择“打开”。
在“解决方案资源管理器”中,右键单击“eShop.AppHost”项目,选择“添加”,然后选择“.NET Aspire 包”。
在搜索文本框中,在现有文本末尾键入“RabbitMQ”。
选择“Aspire.Hosting.RabbitMQ”包。
在“版本”列表中,选择最新的“8.0.0”版本,然后选择“安装”。
如果出现“预览更改”对话框,请选择“应用”。
在“许可接受”对话框中,选择“我接受”。
在“解决方案资源管理器”中,展开“eShop.AppHost”,然后双击“Program.cs”。
找到以下代码行:
var builder = DistributedApplication.CreateBuilder(args);
紧接在该代码之后,添加以下代码以注册 RabbitMQ 服务器:
var messaging = builder.AddRabbitMQ("messaging");
找到以下为 .NET Aspire 业务流程注册 Catalog.API 项目的代码:
var catalogApi = builder.AddProject<Catalog_API>("catalog-api") .WithReference(catalogDb);
若要将 RabbitMQ 服务传递给 Catalog.API 项目,请修改该代码,使之匹配以下代码:
var catalogApi = builder.AddProject<Catalog_API>("catalog-api") .WithReference(catalogDb) .WithReference(messaging);
将 RabbitMQ 添加到 Catalog.API 项目
现在,我们可以在 Catalog.API 项目中安装和配置 RabbitMQ:
在 Visual Studio 的“解决方案资源管理器”中,右键单击 Catalog.API 项目,选择“添加”,然后选择“.NET Aspire 包”。
在搜索文本框中,在现有文本末尾键入“RabbitMQ”。
选择“Aspire.RabbitMQ.Client”包。
在“版本”列表中,选择最新的“8.0.0”版本,然后选择“安装”。
如果出现“预览更改”对话框,请选择“应用”。
在“许可接受”对话框中,选择“我接受”。
在“解决方案资源管理器”中,展开“Catalog.API”项目,然后双击“Program.cs”。
在 Program.cs 文件中,找到以下代码行:
var builder = WebApplication.CreateBuilder(args);
紧接在该行之后,添加以下代码以注册 RabbitMQ 连接:
builder.AddRabbitMQClient("messaging");
将消息发送到 RabbitMQ 队列
当用户请求目录中的项时,我们希望将消息发送到描述请求详细信息的 RabbitMQ 队列。 现在,让我们添加该代码:
在“解决方案资源管理器”中,展开“Catalog.API > Apis”,然后双击“CatalogApi.cs”。
找到以下代码,该代码声明了
GetAllItems()
方法:public static async Task<Results<Ok<PaginatedItems<CatalogItem>>, BadRequest<string>>> GetAllItems( [AsParameters] PaginationRequest paginationRequest, [AsParameters] CatalogServices services) {
若要使用依赖项注入获取与 RabbitMQ 的连接,请修改代码,使之匹配以下行:
public static async Task<Results<Ok<PaginatedItems<CatalogItem>>, BadRequest<string>>> GetAllItems( [AsParameters] PaginationRequest paginationRequest, [AsParameters] CatalogServices services, RabbitMQ.Client.IConnection connection) {
找到以下代码行:
var totalItems = await services.DbContext.CatalogItems .LongCountAsync();
紧接在该行之后,添加以下代码以创建 RabbitMQ 消息传送通道:
var channel = connection.CreateModel();
在下一行,添加以下代码以创建消息队列:
channel.QueueDeclare(queue: "catalogEvents", durable: false, exclusive: false, autoDelete: false, arguments: null);
在下一行,添加以下代码以发送消息:
var body = Encoding.UTF8.GetBytes("Getting all items in the catalog."); channel.BasicPublish(exchange: string.Empty, routingKey: "catalogEvents", mandatory: false, basicProperties: null, body: body);
添加消息使用者项目
为了从 RabbitMQ 队列接收消息,让我们创建一个新项目:
在“解决方案资源管理器”中,右击解决方案,指向“添加”,然后选择“新建项目”。
在“搜索模板”文本框中,键入“控制台”。
选择 C#“控制台应用”模板,然后选择“下一步”。
在“项目名称”文本框中键入“RabbitConsumer”,然后选择“下一步”。
在“框架”列表中,确保已选择“.NET 8.0”,然后选择“创建”。
在“解决方案资源管理器”中,右键单击“AppHost”项目,指向“添加”,然后选择“项目引用”。
在项目列表中,确保已选择“RabbitConsumer”,然后选择“确定”。
在“解决方案资源管理器”中,展开“AppHost”,然后双击“Program.cs”。
查找以下代码:
builder.AddProject<WebApp>("webapp") .WithReference(catalogApi);
紧接在该代码之后,添加以下代码以将 RabbitConsumer 项目添加到 .NET Aspire 业务流程:
builder.AddProject<Projects.RabbitConsumer>("consumers") .WithReference(messaging);
配置消息使用者项目
在可以在新的消息使用者项目中接收消息之前,我们必须将其配置为使用来自 AppHost 的 RabbitMQ 支持服务:
在 Visual Studio 的“解决方案资源管理器”中,右键单击“RabbitConsumer”项目,选择“添加”,然后选择“.NET Aspire 包”。
在搜索文本框中,在现有文本末尾键入“RabbitMQ”。
选择“Aspire.RabbitMQ.Client”包。
在“版本”列表中,选择最新的“8.0.0”版本,然后选择“安装”。
如果出现“预览更改”对话框,请选择“应用”。
在“许可接受”对话框中,选择“我接受”。
在“解决方案资源管理器”中,右键单击“RabbitConsumer”项目,指向“添加”,然后选择“项目引用”。
在项目列表中,确保已选择“eShop.ServiceDefaults”,然后选择“确定”。
在“解决方案资源管理器”中,展开“RabbitConsumer”项目,然后双击“Program.cs”。
删除所有默认代码并将其替换为以下行:
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var builder = Host.CreateApplicationBuilder(args); builder.AddServiceDefaults(); builder.AddRabbitMQClient("messaging"); var host = builder.Build(); host.Run();
请注意,代码使用.NET Aspire 业务流程将 RabbitMQ 服务添加到使用者项目。 你将使用该服务来检索消息。
接收 RabbitMQ 消息
若要接收消息,我们必须创建一个在后台运行的组件来等待消息到达。 使用 BackgroundService
类来完成此任务:
在“解决方案资源管理器”中,右键单击“RabbitConsumer”项目,指向“添加”,然后选择“类”。
在“名称”文本框中键入“CatalogProcessingJob”,然后选择“添加”。
在“CatalogProcessingJob.cs”类中删除所有默认代码,并将其替换为以下行:
namespace RabbitConsumer; using System.Text; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using RabbitMQ.Client; using RabbitMQ.Client.Events; public class CatalogProcessingJob : BackgroundService { private readonly ILogger<CatalogProcessingJob> _logger; private readonly IConfiguration _config; private readonly IServiceProvider _serviceProvider; private IConnection? _messageConnection; private IModel? _messageChannel; private EventingBasicConsumer consumer; public CatalogProcessingJob(ILogger<CatalogProcessingJob> logger, IConfiguration config, IServiceProvider serviceProvider, IConnection? messageConnection) { _logger = logger; _config = config; _serviceProvider = serviceProvider; } protected override Task ExecuteAsync(CancellationToken stoppingToken) { string queueName = "catalogEvents"; _messageConnection = _serviceProvider.GetRequiredService<IConnection>(); _messageChannel = _messageConnection.CreateModel(); _messageChannel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null); consumer = new EventingBasicConsumer(_messageChannel); consumer.Received += ProcessMessageAsync; _messageChannel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer); return Task.CompletedTask; } public override async Task StopAsync(CancellationToken cancellationToken) { await base.StopAsync(cancellationToken); consumer.Received -= ProcessMessageAsync; _messageChannel?.Dispose(); } private void ProcessMessageAsync(object? sender, BasicDeliverEventArgs args) { string messagetext = Encoding.UTF8.GetString(args.Body.ToArray()); _logger.LogInformation("All products retrieved from the catalog at {now}. Message Text: {text}", DateTime.Now, messagetext); var message = args.Body; } }
在“解决方案资源管理器”的“RabbitConsumer”项目中,双击“Program.cs”。
查找以下代码:
builder.AddRabbitMQClient("messaging");
紧接在该行之后添加以下代码:
builder.Services.AddHostedService<CatalogProcessingJob>();
测试解决方案
让我们测试该 RabbitMQ 支持服务以及发送和接收消息的微服务:
在 Visual Studio 中,若要在调试模式下启动应用,请按 F5 或选择“调试”>“开始调试”。
如果出现“启动 Docker Desktop”消息,请选择“是”。 应用将会启动并在浏览器选项卡中显示 .NET Aspire 仪表板。
在 .NET Aspire 仪表板上的“资源”列表中,请注意该列表包含一个名为 messaging 的新容器。 源包括 rabbitmq:3。 该容器运行 RabbitMQ 消息中转站。
在左侧导航窗格中,选择“控制台”。
在“选择资源”列表中,选择“messaging”。 页面显示了 RabbitMQ 中转站的控制台日志。 请注意,最后几条消息表明 RabbitMQ 已完成启动并接受一个连接。 此连接来自接收方 RabbitConsumer 项目。
在左侧导航窗格中,选择“资源”。
在 webapp 项目所在的行中,在“终结点”列中选择一个链接。 Northern Traders 主页随即打开并显示产品目录。 此页面向 RabbitMQ 队列发送一条消息。
切换回 .NET Aspire 仪表板。 在左侧导航窗格中,选择“控制台”。
在“选择资源”列表中,选择“messaging”。 请注意,RabbitQ 已接受第二个连接。 此连接来自 Catalog.API 项目。
在“选择资源”列表中,选择“consumers”。 此日志适用于 RabbitConsumer 项目。 最后一个条目显示消息“正在获取目录中的所有项”。此消息已从 RabbitMQ 检索并已记录。