Freigeben über


Benutzerdefinierte Ressourcenbefehle in .NET.NET Aspire

Jede Ressource im .NET.NET AspireApp-Modell wird als IResource dargestellt und wenn sie dem verteilten Anwendungs-Generatorhinzugefügt wird, ist sie der generische Typ-Parameter der IResourceBuilder<T>-Schnittstelle. Sie verwenden den Ressourcen-Generator-API, um Aufrufe zu verketten, die zugrunde liegende Ressource zu konfigurieren, und in einigen Fällen möchten Sie der Ressource möglicherweise benutzerdefinierte Befehle hinzufügen. Ein häufiges Szenario für das Erstellen eines benutzerdefinierten Befehls kann die Durchführung von Datenbankmigrationen oder das Seeding oder Zurücksetzen einer Datenbank sein. In diesem Artikel erfahren Sie, wie Sie einer Redis Ressource, die den Cache löscht, einen benutzerdefinierten Befehl hinzufügen.

Wichtig

Diese .NET.NET Aspire Dashboard--Befehle sind nur verfügbar, wenn das Dashboard lokal ausgeführt wird. Sie sind nicht verfügbar, wenn Sie das Dashboard in Azure Container Appsausführen.

Hinzufügen von benutzerdefinierten Befehlen zu einer Ressource

Erstellen Sie zunächst eine neue .NET.NET Aspire Starter-App aus den verfügbaren Vorlagen. Um die Lösung aus dieser Vorlage zu erstellen, folgen Sie der schnellstart : Erstellen Sie Ihre erste .NET.NET Aspire Lösung. Fügen Sie nach dem Erstellen dieser Lösung eine neue Klasse namens RedisResourceBuilderExtensions.cs zum App-Hostprojekthinzu. Ersetzen Sie den Inhalt der Datei durch den folgenden Code:

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;
    }
}

Der vorangehende Code:

  • Teilt den Namensraum Aspire.Hosting, damit er für das App-Host-Projekt sichtbar ist.
  • Ist eine static class, damit sie Erweiterungsmethoden enthalten kann.
  • Es definiert eine einzelne Erweiterungsmethode namens WithClearCommand, die die IResourceBuilder<RedisResource> Schnittstelle erweitert.
  • Die WithClearCommand-Methode registriert einen Befehl mit dem Namen clear-cache, der den Cache der Redis Ressource löscht.
  • Die WithClearCommand-Methode gibt die IResourceBuilder<RedisResource> Instanz zurück, um die Verkettung zu ermöglichen.

Die WithCommand-API fügt der Ressource die entsprechenden Anmerkungen hinzu, die im .NET.NET Aspire-Dashboardverwendet werden. Das Dashboard verwendet diese Anmerkungen, um den Befehl in der Benutzeroberfläche zu rendern. Bevor Sie zu weit in diese Details gelangen, stellen wir sicher, dass Sie zunächst die Parameter der WithCommand-Methode verstehen:

  • name: Der Name des befehls, der aufgerufen werden soll.
  • displayName: Der Name des Befehls, der im Dashboard angezeigt werden soll.
  • executeCommand: Die Func<ExecuteCommandContext, Task<ExecuteCommandResult>>, die ausgeführt werden soll, wenn der Befehl aufgerufen wird, wobei die Befehlslogik implementiert wird.
  • updateState: Die Callback-Funktion Func<UpdateCommandStateContext, ResourceCommandState> wird aufgerufen, um den Status "aktiviert" des Befehls zu ermitteln, welcher dann zum Aktivieren oder Deaktivieren des Befehls im Dashboard verwendet wird.
  • iconName: Der Name des Symbols, das im Dashboard angezeigt werden soll. Das Symbol ist optional. Wenn Sie es jedoch angeben, sollte es sich um einen gültigen Fluent UI-Blazor Symbolnamenhandeln.
  • iconVariant: Die Variante des Symbols, das im Dashboard angezeigt werden soll, gültige Optionen sind Regular (Standard) oder Filled.

Befehlslogik ausführen

Der executeCommand Delegat ist der Ort, an dem die Befehlslogik implementiert wird. Dieser Parameter wird als Func<ExecuteCommandContext, Task<ExecuteCommandResult>>definiert. Die ExecuteCommandContext stellt die folgenden Eigenschaften bereit:

  • ExecuteCommandContext.ServiceProvider: Die IServiceProvider Instanz, die zum Auflösen von Diensten verwendet wird.
  • ExecuteCommandContext.ResourceName: Der Name der Ressourceninstanz, für die der Befehl ausgeführt wird.
  • ExecuteCommandContext.CancellationToken: Die CancellationToken, die zum Abbrechen der Befehlsausführung verwendet wird.

Im vorherigen Beispiel wird der executeCommand Delegat als async Methode implementiert, die den Cache der Redis Ressource löscht. Sie delegiert an eine private klassenbezogene Funktion mit dem Namen OnRunClearCacheCommandAsync, um die tatsächliche Cache-Löschung durchzuführen. Beachten Sie den folgenden Code:

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();
}

Der vorangehende Code:

  • Ruft die Verbindungszeichenfolge aus der Redis-Ressource ab.
  • Verbindet mit der Redis Instanz.
  • Ruft die Datenbankinstanz ab.
  • Führt den befehl FLUSHALL aus, um den Cache zu löschen.
  • Gibt eine CommandResults.Success() Instanz zurück, um anzugeben, dass der Befehl erfolgreich war.

Befehlsstatuslogik aktualisieren

Der updateState Delegat ist der Ort, an dem der Befehlsstatus bestimmt wird. Dieser Parameter wird als Func<UpdateCommandStateContext, ResourceCommandState>definiert. Die UpdateCommandStateContext stellt die folgenden Eigenschaften bereit:

  • UpdateCommandStateContext.ServiceProvider: Die IServiceProvider Instanz, die zum Auflösen von Diensten verwendet wird.
  • UpdateCommandStateContext.ResourceSnapshot: Die Momentaufnahme der Ressourceninstanz, für die der Befehl ausgeführt wird.

Die unveränderliche Momentaufnahme ist eine Instanz von CustomResourceSnapshot, die alle möglichen wertvollen Details zur Ressourceninstanz verfügbar macht. Beachten Sie den folgenden Code:

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;
}

Der vorangehende Code:

  • Ruft die Logger-Instanz vom Dienstanbieter ab.
  • Protokolliert die Details des Ressourcenschnappschusses.
  • Gibt ResourceCommandState.Enabled zurück, wenn die Ressource fehlerfrei ist; andernfalls gibt ResourceCommandState.Disabledzurück.

Den benutzerdefinierten Befehl testen

Um den benutzerdefinierten Befehl zu testen, aktualisieren Sie die Program.cs Datei Ihres App-Hostprojekts, um den folgenden Code einzuschließen:

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();

Im vorangehenden Code wird die WithClearCommand-Erweiterungsmethode aufgerufen, um den benutzerdefinierten Befehl zur Redis-Ressource hinzuzufügen. Öffnen Sie die App und navigieren Sie zum .NET.NET Aspire-Dashboard. Sie sollten den benutzerdefinierten Befehl unter der Redis-Ressource aufgeführt sehen. Wählen Sie auf der Dashboard-Seite Ressourcen die Schaltfläche mit den Auslassungspunkten unter der Spalte Aktionen aus:

.NET Aspire Dashboard: Redis Cache-Resource mit benutzerdefiniertem Befehl angezeigt.

Die vorangehende Abbildung zeigt den Befehl Cache löschen, der der Ressource Redis hinzugefügt wurde. Das Symbol zeigt an, dass ein Kaninchen durchgestrichen wird, um anzuzeigen, dass die Geschwindigkeit der abhängigen Ressource zurückgesetzt wird.

Wählen Sie den Befehl Cache löschen aus, um den Cache der Redis Ressource zu löschen. Der Befehl sollte erfolgreich ausgeführt werden, und der Cache sollte gelöscht werden:

.NET Aspire Dashboard: Redis Cacheressource mit ausgeführten benutzerdefinierten Befehlen.

Siehe auch