Comandi di risorse personalizzati in .NET.NET Aspire
Ogni risorsa nel modello di app .NET.NET Aspire è rappresentata come IResource e quando viene aggiunta al generatore di applicazioni distribuite , è il parametro di tipo generico dell'interfaccia IResourceBuilder<T>. È possibile usare il generatore di risorse API per concatenare le chiamate, configurare la risorsa sottostante e, in alcune situazioni, aggiungere comandi personalizzati alla risorsa. Alcuni scenari comuni per la creazione di un comando personalizzato potrebbero includere l'esecuzione di migrazioni di database o il popolamento/reimpostazione di un database. Questo articolo illustra come aggiungere un comando personalizzato a una risorsa Redis che cancella la cache.
Importante
Questi comandi .NET.NET Aspire del dashboard sono disponibili solo quando si esegue il dashboard localmente. Non sono disponibili quando si esegue il dashboard in Azure Container Apps.
Aggiungere comandi personalizzati a una risorsa
Per iniziare, creare una nuova .NET.NET Aspire app di avvio dai modelli disponibili . Per creare la soluzione da questo modello, seguire la Guida rapida : Costruisci la tua prima soluzione .NET.NET Aspire. Dopo aver creato questa soluzione, aggiungere una nuova classe denominata RedisResourceBuilderExtensions.cs al progetto host dell'app . Sostituire il contenuto del file con il codice seguente:
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;
}
}
Il codice precedente:
- Condivide lo spazio dei nomi Aspire.Hosting affinché sia visibile al progetto host dell'app.
- È un
static class
in modo che possa contenere metodi di estensione. - Definisce un singolo metodo di estensione denominato
WithClearCommand
, estendendo l'interfacciaIResourceBuilder<RedisResource>
. - Il metodo
WithClearCommand
registra un comando denominatoclear-cache
che cancella la cache della risorsa Redis. - Il metodo
WithClearCommand
restituisce l'istanza diIResourceBuilder<RedisResource>
per consentire il concatenamento.
L'API WithCommand
aggiunge le annotazioni appropriate alla risorsa, che vengono utilizzate nel dashboard .NET.NET Aspire. Il dashboard usa queste annotazioni per visualizzare il comando nella UI. Prima di entrare troppo in questi dettagli, assicurarsi di comprendere prima i parametri del metodo WithCommand
:
-
name
: nome del comando da richiamare. -
displayName
: nome del comando da visualizzare nel dashboard. -
executeCommand
: ilFunc<ExecuteCommandContext, Task<ExecuteCommandResult>>
da eseguire quando viene richiamato il comando, che è la posizione in cui viene implementata la logica del comando. -
updateState
: il callbackFunc<UpdateCommandStateContext, ResourceCommandState>
viene richiamato per determinare lo stato "abilitato" del comando, che viene usato per abilitare o disabilitare il comando nel dashboard. -
iconName
: nome dell'icona da visualizzare nel dashboard. L'icona è facoltativa, ma quando la si fornisce, deve essere un nome valido dell'icona di Fluent UI Blazor. -
iconVariant
: la variante dell'icona da visualizzare nel dashboard, le opzioni valide sonoRegular
(impostazione predefinita) oFilled
.
Esegui la logica del comando
Il delegato executeCommand
è la posizione in cui viene implementata la logica dei comandi. Questo parametro è definito come Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
. Il ExecuteCommandContext
fornisce le proprietà seguenti:
-
ExecuteCommandContext.ServiceProvider
: L'istanza diIServiceProvider
usata per risolvere i servizi. -
ExecuteCommandContext.ResourceName
: nome dell'istanza della risorsa in cui viene eseguito il comando. -
ExecuteCommandContext.CancellationToken
: il CancellationToken usato per annullare l'esecuzione del comando.
Nell'esempio precedente il delegato executeCommand
viene implementato come metodo async
che cancella la cache della risorsa Redis. Delega a una funzione privata di ambito classe denominata OnRunClearCacheCommandAsync
per eseguire la cancellazione effettiva della cache. Si consideri il codice seguente:
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();
}
Il codice precedente:
- Recupera la stringa di connessione dalla risorsa Redis.
- Si connette all'istanza di Redis.
- Ottiene l'istanza del database.
- Esegue il comando
FLUSHALL
per cancellare la cache. - Restituisce un'istanza di
CommandResults.Success()
per indicare che il comando ha avuto esito positivo.
Aggiornare la logica dello stato del comando
Il delegato updateState
è il punto in cui viene determinato lo stato del comando. Questo parametro è definito come Func<UpdateCommandStateContext, ResourceCommandState>
. Il UpdateCommandStateContext
fornisce le proprietà seguenti:
-
UpdateCommandStateContext.ServiceProvider
: L'istanza diIServiceProvider
usata per risolvere i servizi. -
UpdateCommandStateContext.ResourceSnapshot
: snapshot dell'istanza della risorsa in cui viene eseguito il comando.
Lo snapshot non modificabile è un'istanza di CustomResourceSnapshot
, che espone tutti i tipi di dettagli importanti sull'istanza della risorsa. Si consideri il codice seguente:
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;
}
Il codice precedente:
- Recupera l'istanza del logger dal provider di servizi.
- Registra i dettagli dello snapshot della risorsa.
- Restituisce
ResourceCommandState.Enabled
se la risorsa è funzionante; in caso contrario, restituisceResourceCommandState.Disabled
.
Testare il comando personalizzato
Per testare il comando personalizzato, aggiornare il file di Program.cs del progetto host dell'app per includere il codice seguente:
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();
Il codice precedente chiama il metodo di estensione WithClearCommand
per aggiungere il comando personalizzato alla risorsa Redis. Avvia l'app e vai al dashboard .NET.NET Aspire. Il comando personalizzato dovrebbe essere elencato sotto la risorsa Redis. Nella pagina Risorse del dashboard, selezionare il pulsante con i puntini di sospensione nella colonna Azioni:
L'immagine precedente mostra il comando cancella cache aggiunto alla risorsa Redis. L'icona viene visualizzata come un coniglio barrato per indicare che la velocità della risorsa dipendente viene azzerata.
Selezionare il comando Cancella cache per cancellare la cache della risorsa Redis. Il comando deve essere eseguito correttamente e la cache deve essere cancellata: