Comandos de recursos personalizados no .NET.NET Aspire
Cada recurso no modelo de aplicativo .NET.NET Aspire é representado como um IResource e, quando adicionado ao do construtor de aplicativos distribuído, é o parâmetro de tipo genérico da interface IResourceBuilder<T>. Use o resource builder API para encadear chamadas, configurar o recurso subjacente e, em algumas situações, talvez queira adicionar comandos personalizados ao recurso. Algum cenário comum para criar um comando personalizado pode ser a execução de migrações de banco de dados ou a propagação/redefinição de um banco de dados. Neste artigo, você aprenderá a adicionar um comando personalizado a um recurso de Redis que limpa o cache.
Importante
Esses .NET.NET Aspire comandos de do painel 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 por criar uma nova aplicação inicial .NET.NET Aspire a partir dos modelos disponíveis. Para criar a solução a partir deste modelo, siga o Guia de início rápido: crie 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 dashboard .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>>
ser executado quando o comando é invocado, que é onde a lógica de comando é implementada. -
updateState
: O retorno de chamadaFunc<UpdateCommandStateContext, ResourceCommandState>
é invocado para determinar o estado de "ativado" do comando, que é usado para habilitar ou desabilitar o comando no painel. -
iconName
: O nome do ícone a ser exibido no painel. O ícone é opcional, mas quando você o fornece, ele deve ser um Fluent UI válido Blazor nome do ícone. -
iconVariant
: A variante do ícone a ser exibido no painel, as opções válidas sãoRegular
(padrão) ouFilled
.
Executar lógica de comando
O delegado executeCommand
é onde a lógica de comando é implementada. Este parâmetro é definido como um Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
. O ExecuteCommandContext
fornece as seguintes propriedades:
-
ExecuteCommandContext.ServiceProvider
: A instânciaIServiceProvider
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 a cache do recurso Redis. Ele delega a uma função privada de escopo de classe chamada OnRunClearCacheCommandAsync
para executar a limpeza de cache real. 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 Redis.
- Obtém a instância do banco de dados.
- Executa o comando
FLUSHALL
para limpar o cache. - Retorna uma instância
CommandResults.Success()
para indicar que o comando foi bem-sucedido.
Atualizar lógica de estado do comando
A delegação updateState
é onde o estado do comando é determinado. Este parâmetro é definido como um Func<UpdateCommandStateContext, ResourceCommandState>
. O UpdateCommandStateContext
fornece as seguintes propriedades:
-
UpdateCommandStateContext.ServiceProvider
: A instânciaIServiceProvider
usada para resolver serviços. -
UpdateCommandStateContext.ResourceSnapshot
: O instantâneo da instância de recurso na qual o comando está sendo executado.
O instantâneo imutável é uma instância de CustomResourceSnapshot
, que revela 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 em boas condições; caso contrário, retornaResourceCommandState.Disabled
.
Testar o comando personalizado
Para testar o comando personalizado, atualize o arquivo de 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 sob o recurso Redis. Na página de Recursos do painel, selecione o botão de reticências na coluna de Ações:
A imagem anterior mostra o comando Limpar cache que foi adicionado ao recurso Redis. O ícone é exibido quando um coelho risca para indicar que a velocidade do recurso dependente está sendo limpa.
Selecione o comando Limpar cache para limpar o cache do recurso Redis. O comando deve ser executado com êxito e o cache deve ser limpo:
Ver também
- Visão geral da orquestração .NET.NET Aspire
- Painel .NET.NET Aspire: Ações do submenu de Recursos