Aspire中的每个资源都是IResource,在添加到分布式应用程序构建器时,它是IResourceBuilder<T>接口的泛型类型参数。 可以使用 资源生成器 API 链接调用、配置基础资源,在某些情况下,可能需要向资源添加自定义命令。 创建自定义命令的一些常见情况可能是运行数据库迁移或播种/重置数据库。 本文介绍如何将自定义命令添加到 Redis 清除缓存的资源。
重要
这些 Aspire 仪表板 命令仅在本地运行仪表板时才可用。 在 Azure Container Apps中运行仪表板时,它们不可用。
将自定义命令添加到资源
首先从Aspire创建新的初学者应用。 若要从此模板创建解决方案,请按照 快速入门:生成第一个 Aspire 解决方案。 创建此解决方案后,将名为 RedisResourceBuilderExtensions.cs 的新类添加到 AppHost 项目。 将文件的内容替换为以下代码:
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)
{
var commandOptions = new CommandOptions
{
UpdateState = OnUpdateResourceState,
IconName = "AnimalRabbitOff",
IconVariant = IconVariant.Filled
};
builder.WithCommand(
name: "clear-cache",
displayName: "Clear Cache",
executeCommand: context => OnRunClearCacheCommandAsync(builder, context),
commandOptions: commandOptions);
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共享命名空间,使其对 AppHost 项目可见。
- 是一个
static class,以便它可以包含扩展方法。 - 它定义了一个名为
WithClearCommand的扩展方法,该方法用于扩展IResourceBuilder<RedisResource>接口。 - 该方法
WithClearCommand注册一个名为clear-cache清除资源缓存的 Redis 命令。 -
WithClearCommand方法返回IResourceBuilder<RedisResource>实例以允许链式调用。
API WithCommand 将适当的批注添加到资源上,这些批注在仪表板Aspire中被消耗。 仪表板使用这些注释在 UI 中呈现命令。 在深入了解这些详细信息之前,我们先确保先了解方法的参数 WithCommand :
-
name:要调用的命令的名称。 -
displayName:要显示在仪表板中的命令的名称。 -
executeCommand:命令被调用时要运行的Func<ExecuteCommandContext, Task<ExecuteCommandResult>>,即命令逻辑实现的地方。 -
updateStateFunc<UpdateCommandStateContext, ResourceCommandState>:调用回调以确定命令的“已启用”状态,该状态用于启用或禁用仪表板中的命令。 -
iconName:要显示在仪表板中的图标的名称。 该图标是可选的,但当你提供它时,它应该是一个有效的 Fluent UI Blazor 图标名称。 -
iconVariant:仪表板中显示的图标的变体,有效选项为Regular(默认)或Filled。
执行指令逻辑
executeCommand 委托是实现命令逻辑之处。 此参数定义为一个Func<ExecuteCommandContext, Task<ExecuteCommandResult>>。
ExecuteCommandContext 提供以下属性:
-
ExecuteCommandContext.ServiceProvider:IServiceProvider用于解析服务的实例。 -
ExecuteCommandContext.ResourceName:正在执行命令的资源实例的名称。 -
ExecuteCommandContext.CancellationToken:用于取消命令执行的 CancellationToken。
在前面的示例中,executeCommand 委托被实现为一种用于清除 async 资源缓存的 Redis 方法。 它将委托给名为 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。
测试自定义命令
若要测试自定义命令,请更新 AppHost 项目的 AppHost.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 资源。 运行应用并导航到 Aspire 仪表板。 您应该会看到 Redis 资源下列出的自定义命令。 在仪表板的 资源 页上,选择 操作 列中的省略号按钮:
上述图像显示了已添加在 资源中的 Redis 命令。 图标显示为兔子交叉,以指示正在清除依赖资源的速度。
选择 “清除缓存 ”命令以清除资源的缓存 Redis 。 该命令应成功执行,应清除缓存: