.NET .NET Aspire 中的自定义资源命令
.NET .NET Aspire 应用模型 中的每个资源都表示为 IResource,当添加到 分布式应用程序生成器时,它是 IResourceBuilder<T> 接口的泛型类型参数。 可以使用 资源生成器 API 链接调用、配置基础资源,在某些情况下,可能需要向资源添加自定义命令。 创建自定义命令的一些常见情况可能是运行数据库迁移或播种/重置数据库。 本文介绍如何将自定义命令添加到清除缓存的 Redis 资源。
重要
这些 .NET.NET Aspire 仪表板 命令仅在本地运行仪表板时才可用。 在 Azure Container Apps中运行仪表板时,它们不可用。
将自定义命令添加到资源
首先从 可用模板创建新的 .NET.NET Aspire Starter App。 若要从此模板创建解决方案,请遵循 快速入门:生成第一个 .NET.NET Aspire 解决方案。 创建此解决方案后,将名为 RedisResourceBuilderExtensions.cs 的新类添加到 应用主机项目。 将文件的内容替换为以下代码:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace Aspire.Hosting;
internal static class RedisResourceBuilderExtensions
{
public static IResourceBuilder<RedisResource> WithClearCommand(
this IResourceBuilder<RedisResource> builder)
{
builder.WithCommand(
name: "clear-cache",
displayName: "Clear Cache",
executeCommand: context => OnRunClearCacheCommandAsync(builder, context),
updateState: OnUpdateResourceState,
iconName: "AnimalRabbitOff",
iconVariant: IconVariant.Filled);
return builder;
}
private static async Task<ExecuteCommandResult> OnRunClearCacheCommandAsync(
IResourceBuilder<RedisResource> builder,
ExecuteCommandContext context)
{
var connectionString = await builder.Resource.GetConnectionStringAsync() ??
throw new InvalidOperationException(
$"Unable to get the '{context.ResourceName}' connection string.");
await using var connection = ConnectionMultiplexer.Connect(connectionString);
var database = connection.GetDatabase();
await database.ExecuteAsync("FLUSHALL");
return CommandResults.Success();
}
private static ResourceCommandState OnUpdateResourceState(
UpdateCommandStateContext context)
{
var logger = context.ServiceProvider.GetRequiredService<ILogger<Program>>();
if (logger.IsEnabled(LogLevel.Information))
{
logger.LogInformation(
"Updating resource state: {ResourceSnapshot}",
context.ResourceSnapshot);
}
return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy
? ResourceCommandState.Enabled
: ResourceCommandState.Disabled;
}
}
前面的代码:
- 共享 Aspire.Hosting 命名空间,使其对应用主机项目可见。
- 是一个
static class
,以便它可以包含扩展方法。 - 它定义一个名为
WithClearCommand
的扩展方法,从而扩展IResourceBuilder<RedisResource>
接口。 -
WithClearCommand
方法注册一个名为clear-cache
的命令,用于清除 Redis 资源的缓存。 -
WithClearCommand
方法返回IResourceBuilder<RedisResource>
实例以允许链式调用。
WithCommand
API 将适当的注释添加到资源,这些注释会在 .NET.NET Aspire 仪表板中被使用。 仪表板使用这些注释在 UI 中呈现命令。 在深入了解这些详细信息之前,我们先确保先了解 WithCommand
方法的参数:
-
name
:要调用的命令的名称。 -
displayName
:要显示在仪表板中的命令的名称。 -
executeCommand
:调用命令时要运行的Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
,即实现命令逻辑的位置。 -
updateState
:调用Func<UpdateCommandStateContext, ResourceCommandState>
回调以确定命令的“已启用”状态,该状态用于启用或禁用仪表板中的命令。 -
iconName
:要显示在仪表板中的图标的名称。 该图标是可选的,但当你提供它时,它应该是一个有效的 Fluent UI Blazor 图标名称。 -
iconVariant
:仪表板中显示的图标的变体,有效选项为Regular
(默认)或Filled
。
执行指令逻辑
executeCommand
委托是实现命令逻辑之处。 此参数定义为 Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
。
ExecuteCommandContext
提供以下属性:
-
ExecuteCommandContext.ServiceProvider
:用于解析服务的IServiceProvider
实例。 -
ExecuteCommandContext.ResourceName
:正在执行命令的资源实例的名称。 -
ExecuteCommandContext.CancellationToken
:用于取消命令执行的 CancellationToken。
在前面的示例中,executeCommand
委托被实现为一种用于清除 Redis 资源缓存的 async
方法。 它将委托给名为 OnRunClearCacheCommandAsync
的专用类范围函数,以执行实际的缓存清除。 请考虑以下代码:
private static async Task<ExecuteCommandResult> OnRunClearCacheCommandAsync(
IResourceBuilder<RedisResource> builder,
ExecuteCommandContext context)
{
var connectionString = await builder.Resource.GetConnectionStringAsync() ??
throw new InvalidOperationException(
$"Unable to get the '{context.ResourceName}' connection string.");
await using var connection = ConnectionMultiplexer.Connect(connectionString);
var database = connection.GetDatabase();
await database.ExecuteAsync("FLUSHALL");
return CommandResults.Success();
}
前面的代码:
- 从 Redis 资源检索连接字符串。
- 连接到 Redis 实例。
- 获取数据库实例。
- 执行
FLUSHALL
命令以清除缓存。 - 返回一个
CommandResults.Success()
实例,指示命令成功。
更新命令状态逻辑
updateState
委托用于确定命令状态。 此参数定义为 Func<UpdateCommandStateContext, ResourceCommandState>
。
UpdateCommandStateContext
提供以下属性:
-
UpdateCommandStateContext.ServiceProvider
:用于解析服务的IServiceProvider
实例。 -
UpdateCommandStateContext.ResourceSnapshot
:执行命令的资源实例的快照。
不可变快照是 CustomResourceSnapshot
的实例,它公开有关资源实例的各种有价值的详细信息。 请考虑以下代码:
private static ResourceCommandState OnUpdateResourceState(
UpdateCommandStateContext context)
{
var logger = context.ServiceProvider.GetRequiredService<ILogger<Program>>();
if (logger.IsEnabled(LogLevel.Information))
{
logger.LogInformation(
"Updating resource state: {ResourceSnapshot}",
context.ResourceSnapshot);
}
return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy
? ResourceCommandState.Enabled
: ResourceCommandState.Disabled;
}
前面的代码:
- 从服务提供商检索记录器实例。
- 记录资源快照详细信息。
- 如果资源正常,则返回
ResourceCommandState.Enabled
;否则,它将返回ResourceCommandState.Disabled
。
测试自定义命令
若要测试自定义命令,请更新应用主机项目的 Program.cs 文件以包含以下代码:
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache")
.WithClearCommand();
var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");
builder.AddProject<Projects.AspireApp_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(cache)
.WaitFor(cache)
.WithReference(apiService)
.WaitFor(apiService);
builder.Build().Run();
前面的代码调用 WithClearCommand
扩展方法,将自定义命令添加到 Redis 资源。 运行应用并导航到 .NET.NET Aspire 仪表板。 您应该会看到 Redis 资源下列出的自定义命令。 在仪表板的 资源 页上,选择 操作 列中的省略号按钮:
上述图像显示了已添加在 Redis 资源中的 清除缓存 命令。 图标显示为兔子交叉,以指示正在清除依赖资源的速度。
选择 清除缓存 命令以清除 Redis 资源的缓存。 该命令应成功执行,应清除缓存: