[FIXED] Wie kann ich einen Dienst während der Laufzeit in ASP.NET Core 5 dynamisch neu konfigurieren?

Ausgabe

Ich verwende die Google-Authentifizierung in meiner Web-App und die OAuth-Schlüssel sind derzeit in ConfigureServices fest codiert:

services.AddAuthentication()
    .AddGoogle(options =>
    {
        options.ClientId = "my-client-id";
        options.ClientSecret = "my-client-secret";
    });

Ich möchte dem Site-Administrator jedoch die Möglichkeit geben, die ClientId und das ClientSecret auf der Einstellungsseite der Web-App zu ändern, vorzugsweise ohne den Server neu starten zu müssen.

Dazu müsste ich irgendwie eine Neukonfiguration des Google-Dienstes und des GoogleOptions-Objekts auslösen, wenn der Benutzer auf der Einstellungsseite auf „Speichern“ klickt. Damit habe ich Probleme. Außerdem möchte ich diese Einstellungen in einem EF Core DbContext und nicht in einer physischen Konfigurationsdatei speichern.

Bisher habe ich versucht, die Einstellungen in eine separate Klasse zu verschieben, die IPostConfigureOptions implementiert. Dies sollte es mir ermöglichen, meinen Datenbankkontext einzufügen, da PostConfigure laut Dokumentation ausgeführt werden soll, nachdem alle anderen Konfigurationen erfolgt sind. Die Einstellungen werden korrekt aus dieser neuen Klasse geladen, aber die Injektion des DB-Kontexts schlägt mit der folgenden Ausnahme fehl:

System.InvalidOperationException: Cannot consume scoped service 'AppDatabase' from singleton 'IOptionsMonitor`1[GoogleOptions]'

Das ist seltsam, weil ConfigureGoogleOptions als Scoped und nicht als Singleton registriert ist.

Hier ist meine Optionsklasse:

public class ConfigureGoogleOptions : IPostConfigureOptions<GoogleOptions>
{
    private readonly AppDatabase database;

    public ConfigureGoogleOptions(AppDatabase database)
    {
        this.database = database;
    }
    
    public void PostConfigure(string name, GoogleOptions options)
    {
        options.ClientId = "my-client-id.apps.googleusercontent.com";
        options.ClientSecret = "my-client-secret";
    }
}

Und die Registrierung in ConfigureServices:

services.AddScoped<IPostConfigureOptions<GoogleOptions>, ConfigureGoogleOptions>();

Selbst wenn die Datenbankinjektion funktioniert hat, gibt es noch ein zweites Problem. Die PostConfigureFunktion in meiner Klasse wird nur einmal aufgerufen, nachdem die Anwendung gestartet wurde, und nie wieder. Ich gehe davon aus, dass die Einstellungen irgendwo zwischengespeichert werden, und ich weiß nicht, wie ich diesen Cache ungültig machen oder deaktivieren kann, damit ich Werte dynamisch bereitstellen kann.

Kurze Zusammenfassung / tl;dr:

Ich möchte die ClientId- und ClientSecret-Einstellungen des Google OAuth-Dienstes aus meiner eigenen Datenbank laden und sie dynamisch ändern können, während der Server läuft.

Lösung

Intern wird der Google-Handler verwendet IOptionsMonitor<GoogleOptions>, um das GoogleOptions einmal oder bis zum Neuladen abzurufen (z. B. wenn die Optionen aus einer Konfigurationsdatei gebunden sind und das Speichern der Datei das Neuladen auslöst). Der IOptionsMonitorwird intern verwendet IOptionsMonitorCacheund dieser Cache wird als Singleton registriert. Die Optionsinstanz, von der Sie erhalten, IOptionsMonitor<GoogleOptions>ist also dieselbe (Referenz) wie die AuthenticationHandler<GoogleOptions>.Options, die für verschiedene Operationen innerhalb des Handlers verwendet wird. Sogar anderer Code sollte bei Verwendung dieser Optionen korrekt von IOptionsMonitor<GoogleOptions>.

Um die Optionen zur Laufzeit zu ändern, ist es einfach so:

//inject the IOptionsMonitor<GoogleOptions> into _googleOptionsMonitor;
var runtimeOptions = _googleOptionsMonitor.Get(GoogleDefaults.AuthenticationScheme);
//you change properties of runtimeOptions here
//...

Der wichtige Punkt hier ist, dass wir GoogleDefaults.AuthenticationSchemeals Schlüssel verwenden müssen, um die richtige Instanz von Optionen zu erhalten. Der IOptionsMonitor.CurrentValueverwendet den Standardschlüssel von Options.DefaultName(der eine leere Zeichenfolge ist).


Beantwortet von –
King King


Antwort geprüft von –
Gilberto Lyons (FixError Admin)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like