Comandos de recursos personalizados no .NET.NET Aspire
Cada recurso no modelo de aplicativo
Importante
Esses comandos .NET.NET Aspire dashboard só estão disponíveis ao executar o painel localmente. Eles não estão disponíveis ao executar o painel no Azure Container Apps.
Adicionar comandos personalizados a um recurso
Comece criando um novo aplicativo inicial .NET.NET Aspire a partir dos modelos disponíveis. Para criar a solução com base nesse modelo, siga o início rápido do : criar sua primeira solução .NET.NET Aspire. Depois de criar essa solução, adicione uma nova classe chamada RedisResourceBuilderExtensions.cs ao projeto de host do aplicativo . Substitua o conteúdo do arquivo pelo seguinte código:
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;
}
}
O código anterior:
- Compartilha o namespace Aspire.Hosting para que ele fique visível para o projeto de host do aplicativo.
- É um
static class
para que possa conter métodos de extensão. - Ele define um único método de extensão chamado
WithClearCommand
, estendendo a interfaceIResourceBuilder<RedisResource>
. - O método
WithClearCommand
registra um comando chamadoclear-cache
que limpa o cache do recurso Redis. - O método
WithClearCommand
retorna a instânciaIResourceBuilder<RedisResource>
para permitir o encadeamento.
A API WithCommand
adiciona as anotações apropriadas ao recurso, que são consumidas no painel .NET.NET Aspire. O painel usa essas anotações para renderizar o comando na interface do usuário. Antes de ir muito longe nesses detalhes, vamos garantir que você primeiro entenda os parâmetros do método WithCommand
:
-
name
: o nome do comando a ser invocado. -
displayName
: o nome do comando a ser exibido no painel. -
executeCommand
: oFunc<ExecuteCommandContext, Task<ExecuteCommandResult>>
a ser executado quando o comando é invocado, local onde a lógica do comando é implementada. -
updateState
: O callbackFunc<UpdateCommandStateContext, ResourceCommandState>
é invocado para determinar o estado de habilitação do comando, que é usado para habilitar ou desabilitar o comando no dashboard. -
iconName
: o nome do ícone a ser exibido no painel. O ícone é opcional, mas quando você o fornecer, ele deve ter um nome válido de ícone Fluent UI. -
iconVariant
: a variante do ícone a ser exibida no painel, as opções válidas sãoRegular
(padrão) ouFilled
.
Executar a lógica do comando
O delegado executeCommand
é onde a lógica de comando é implementada. Esse parâmetro é definido como um Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
. O ExecuteCommandContext
fornece as seguintes propriedades:
-
ExecuteCommandContext.ServiceProvider
: a instância deIServiceProvider
usada para resolver serviços. -
ExecuteCommandContext.ResourceName
: o nome da instância de recurso na qual o comando está sendo executado. -
ExecuteCommandContext.CancellationToken
: o CancellationToken usado para cancelar a execução do comando.
No exemplo anterior, o delegado executeCommand
é implementado como um método async
que limpa o cache do recurso de Redis. Ele delega para uma função de escopo de classe privada chamada OnRunClearCacheCommandAsync
para realizar a limpeza efetiva do cache. Considere o seguinte código:
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();
}
O código anterior:
- Recupera a cadeia de conexão do recurso Redis.
- Conecta-se à instância de Redis.
- Obtém a instância do banco de dados.
- Executa o comando
FLUSHALL
para limpar o cache. - Retorna uma instância de
CommandResults.Success()
para indicar que o comando foi bem-sucedido.
Atualizar lógica de estado do comando
O delegado updateState
é onde o estado do comando é determinado. Esse parâmetro é definido como um Func<UpdateCommandStateContext, ResourceCommandState>
. O UpdateCommandStateContext
fornece as seguintes propriedades:
-
UpdateCommandStateContext.ServiceProvider
: a instância deIServiceProvider
usada para resolver serviços. -
UpdateCommandStateContext.ResourceSnapshot
: o instantâneo da instância do recurso na qual o comando está sendo executado atualmente.
O instantâneo imutável é uma instância de CustomResourceSnapshot
, que expõe todos os tipos de detalhes valiosos sobre a instância de recurso. Considere o seguinte código:
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;
}
O código anterior:
- Recupera a instância do registrador do provedor de serviços.
- Registra os detalhes do instantâneo do recurso.
- Retorna
ResourceCommandState.Enabled
se o recurso estiver íntegro; caso contrário, retornaResourceCommandState.Disabled
.
Testar o comando personalizado
Para testar o comando personalizado, atualize o arquivo Program.cs do projeto de host do aplicativo para incluir o seguinte código:
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();
O código anterior chama o método de extensão WithClearCommand
para adicionar o comando personalizado ao recurso Redis. Execute o aplicativo e navegue até o painel .NET.NET Aspire. Você deve ver o comando personalizado listado no recurso Redis. Na página Recursos do painel, selecione o botão de mais opções na coluna Ações.
A imagem anterior mostra o comando Limpar cache que foi adicionado ao recurso Redis. O ícone é exibido como um coelho risca para indicar que a velocidade do recurso dependente está sendo desmarcada.
Selecione o comando Limpar cache para limpar o cache do recurso de Redis. O comando deve ser executado com êxito e o cache deve ser limpo: