Sdílet prostřednictvím


Detekce změn pomocí tokenů změn v ASP.NET Core

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Upozorňující

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v tématu .NET a .NET Core Zásady podpory. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Token změn je univerzální stavební blok nízké úrovně, který se používá ke sledování změn stavu.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

IChangeToken – rozhraní

IChangeToken šíří oznámení, že došlo ke změně. IChangeToken se nachází v Microsoft.Extensions.Primitives oboru názvů. Balíček NuGet Microsoft.Extensions.Primitives se implicitně poskytuje aplikacím ASP.NET Core.

IChangeToken má dvě vlastnosti:

  • ActiveChangeCallbacks označuje, jestli token proaktivně vyvolává zpětná volání. Pokud ActiveChangedCallbacks je nastavená hodnota false, zpětné volání se nikdy nevolá a aplikace se musí dotazovat HasChanged na změny. Token je také možné nikdy zrušit, pokud nedojde k žádným změnám nebo se základní naslouchací proces změn odstraní nebo zakáže.
  • HasChanged obdrží hodnotu, která označuje, jestli došlo ke změně.

Rozhraní IChangeToken zahrnuje RegisterChangeCallback(Action<Object>, Object), která registruje zpětné volání, které je vyvoláno při změně tokenu. HasChanged musí být nastavena před vyvolání zpětného volání.

ChangeToken – třída

ChangeToken je statická třída používaná k šíření oznámení, že došlo ke změně. ChangeToken se nachází v Microsoft.Extensions.Primitives oboru názvů. Balíček NuGet Microsoft.Extensions.Primitives se implicitně poskytuje aplikacím ASP.NET Core.

Metoda ChangeToken.OnChange(Func<IChangeToken>, Action) zaregistruje Action volání při každé změně tokenu:

  • Func<IChangeToken> vytvoří token.
  • Action je volána při změně tokenu.

ChangeToken.OnChange <TState>(Func<IChangeToken>, Action<TState, TState>) přetížení přebírá další TState parametr, který je předán do příjemce Actiontokenu .

OnChange vrátí hodnotu IDisposable. Volání Dispose zastaví naslouchání tokenu dalším změnám a uvolní prostředky tokenu.

Příklad použití tokenů změn v ASP.NET Core

Tokeny změn se používají v hlavních oblastech ASP.NET Core k monitorování změn objektů:

  • Pro monitorování změn souborů IFileProviderWatch metoda vytvoří IChangeToken pro zadané soubory nebo složku, které se mají sledovat.
  • IChangeToken tokeny lze přidat do položek mezipaměti, aby se při změně aktivovaly vyřazení mezipaměti.
  • U TOptions změn má výchozí OptionsMonitor<TOptions> implementace IOptionsMonitor<TOptions> přetížení, které přijímá jednu nebo více IOptionsChangeTokenSource<TOptions> instancí. Každá instance vrátí metodu IChangeToken pro registraci zpětného volání oznámení o změnách pro sledování změn možností.

Monitorování změn konfigurace

Ve výchozím nastavení ASP.NET šablony Core používají konfigurační soubory JSON (appsettings.jsonappsettings.Development.jsonaappsettings.Production.json) k načtení nastavení konfigurace aplikace.

Tyto soubory se konfigurují pomocí metody ConfigurationBuilder rozšíření AddJsonFile(IConfigurationBuilder, String, Boolean, Boolean), která přijímá reloadOnChange parametr. reloadOnChange označuje, jestli by se při změně souboru měla znovu načíst konfigurace. Toto nastavení se zobrazí v Host metodě CreateDefaultBuilderusnadnění:

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, 
          reloadOnChange: true);

Konfigurace založená na souborech je reprezentována .FileConfigurationSource FileConfigurationSource používá IFileProvider k monitorování souborů.

Ve výchozím nastavení IFileMonitor je poskytována nástrojem PhysicalFileProvider, který používá FileSystemWatcher ke sledování změn konfiguračního souboru.

Ukázková aplikace ukazuje dvě implementace pro monitorování změn konfigurace. Pokud se některý ze appsettings souborů změní, spustí se v obou implementacích monitorování souborů vlastní kód – ukázková aplikace zapíše zprávu do konzoly.

Konfigurační soubor FileSystemWatcher může aktivovat více zpětných volání tokenů pro změnu jednoho konfiguračního souboru. Aby se zajistilo, že se vlastní kód spustí jenom jednou, když se aktivuje více zpětných volání tokenů, zkontroluje implementace ukázky hodnoty hash souboru. Ukázka používá hashování souborů SHA1. Opakování se implementuje s exponenciálním zpětným vypnutím.

Utilities/Utilities.cs:

public static byte[] ComputeHash(string filePath)
{
    var runCount = 1;

    while(runCount < 4)
    {
        try
        {
            if (File.Exists(filePath))
            {
                using (var fs = File.OpenRead(filePath))
                {
                    return System.Security.Cryptography.SHA1
                        .Create().ComputeHash(fs);
                }
            }
            else 
            {
                throw new FileNotFoundException();
            }
        }
        catch (IOException ex)
        {
            if (runCount == 3)
            {
                throw;
            }

            Thread.Sleep(TimeSpan.FromSeconds(Math.Pow(2, runCount)));
            runCount++;
        }
    }

    return new byte[20];
}

Jednoduchý token změny spuštění

Zaregistrujte zpětné volání příjemce Action tokenu pro oznámení o změnách do tokenu opětovného načtení konfigurace.

V Startup.Configure:

ChangeToken.OnChange(
    () => config.GetReloadToken(),
    (state) => InvokeChanged(state),
    env);

config.GetReloadToken() poskytuje token. Zpětné volání je InvokeChanged metoda:

private void InvokeChanged(IWebHostEnvironment env)
{
    byte[] appsettingsHash = ComputeHash("appSettings.json");
    byte[] appsettingsEnvHash = 
        ComputeHash($"appSettings.{env.EnvironmentName}.json");

    if (!_appsettingsHash.SequenceEqual(appsettingsHash) || 
        !_appsettingsEnvHash.SequenceEqual(appsettingsEnvHash))
    {
        _appsettingsHash = appsettingsHash;
        _appsettingsEnvHash = appsettingsEnvHash;

        WriteConsole("Configuration changed (Simple Startup Change Token)");
    }
}

Zpětné state volání se používá k předání IWebHostEnvironment, což je užitečné pro určení správného appsettings konfiguračního souboru pro monitorování (například appsettings.Development.json v prostředí pro vývoj). Hodnoty hash souborů se používají k tomu, aby příkaz neběžil WriteConsole několikrát kvůli více zpětným voláním tokenů, když se konfigurační soubor změnil pouze jednou.

Tento systém běží, pokud je aplikace spuštěná a uživatel ji nemůže zakázat.

Monitorování změn konfigurace jako služby

Ukázka implementuje:

  • Základní monitorování spouštěcích tokenů
  • Monitorování jako služba
  • Mechanismus pro povolení a zakázání monitorování.

Ukázka vytvoří IConfigurationMonitor rozhraní.

Extensions/ConfigurationMonitor.cs:

public interface IConfigurationMonitor
{
    bool MonitoringEnabled { get; set; }
    string CurrentState { get; set; }
}

Konstruktor implementované třídy , ConfigurationMonitorzaregistruje zpětné volání pro oznámení o změnách:

public ConfigurationMonitor(IConfiguration config, IWebHostEnvironment env)
{
    _env = env;

    ChangeToken.OnChange<IConfigurationMonitor>(
        () => config.GetReloadToken(),
        InvokeChanged,
        this);
}

public bool MonitoringEnabled { get; set; } = false;
public string CurrentState { get; set; } = "Not monitoring";

config.GetReloadToken() poskytuje token. InvokeChanged je metoda zpětného volání. V state této instanci je odkaz na IConfigurationMonitor instanci, která se používá pro přístup ke stavu monitorování. Používají se dvě vlastnosti:

  • MonitoringEnabled: Označuje, jestli má zpětné volání spustit vlastní kód.
  • CurrentState: Popisuje aktuální stav monitorování pro použití v uživatelském rozhraní.

Metoda InvokeChanged se podobá dřívějšímu přístupu s tím rozdílem, že:

  • Nespouští jeho kód, pokud MonitoringEnabled není true.
  • Vypíše aktuální výsledek state výstupu WriteConsole .
private void InvokeChanged(IConfigurationMonitor state)
{
    if (MonitoringEnabled)
    {
        byte[] appsettingsHash = ComputeHash("appSettings.json");
        byte[] appsettingsEnvHash = 
            ComputeHash($"appSettings.{_env.EnvironmentName}.json");

        if (!_appsettingsHash.SequenceEqual(appsettingsHash) || 
            !_appsettingsEnvHash.SequenceEqual(appsettingsEnvHash))
        {
            string message = $"State updated at {DateTime.Now}";
          

            _appsettingsHash = appsettingsHash;
            _appsettingsEnvHash = appsettingsEnvHash;

            WriteConsole("Configuration changed (ConfigurationMonitor Class) " +
                $"{message}, state:{state.CurrentState}");
        }
    }
}

Instance ConfigurationMonitor je zaregistrovaná jako služba v Startup.ConfigureServices:

services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();

Stránka Index nabízí uživateli kontrolu nad monitorováním konfigurace. Instance IConfigurationMonitor je vložena IndexModeldo .

Pages/Index.cshtml.cs:

public IndexModel(
    IConfiguration config, 
    IConfigurationMonitor monitor, 
    FileService fileService)
{
    _config = config;
    _monitor = monitor;
    _fileService = fileService;
}

Monitorování konfigurace (_monitor) slouží k povolení nebo zakázání monitorování a nastavení aktuálního stavu pro zpětnou vazbu uživatelského rozhraní:

public IActionResult OnPostStartMonitoring()
{
    _monitor.MonitoringEnabled = true;
    _monitor.CurrentState = "Monitoring!";

    return RedirectToPage();
}

public IActionResult OnPostStopMonitoring()
{
    _monitor.MonitoringEnabled = false;
    _monitor.CurrentState = "Not monitoring";

    return RedirectToPage();
}

Po OnPostStartMonitoring aktivaci se povolí monitorování a aktuální stav se vymaže. Když OnPostStopMonitoring se aktivuje, monitorování je zakázané a stav je nastavený tak, aby odrážel, že se monitorování neprojevuje.

Tlačítka v uživatelském rozhraní umožňují a zakazují monitorování.

Pages/Index.cshtml:

<button class="btn btn-success" asp-page-handler="StartMonitoring">
    Start Monitoring
</button>

<button class="btn btn-danger" asp-page-handler="StopMonitoring">
    Stop Monitoring
</button>

Monitorování změn souborů uložených v mezipaměti

Obsah souboru lze ukládat do mezipaměti pomocí .IMemoryCache Ukládání do mezipaměti je popsáno v tématu Mezipaměť v paměti . Bez provedení dalších kroků, jako je implementace popsaná níže, se zastaralá (zastaralá) data vrátí z mezipaměti, pokud se zdrojová data změní.

Například při obnovování období vypršení platnosti se stavem zdrojového souboru uloženého v mezipaměti vede k zastaralým datům souborů uložených v mezipaměti. Každá žádost o data prodlužuje dobu vypršení platnosti, ale soubor se nikdy znovu nenačte do mezipaměti. Na všechny funkce aplikace, které používají obsah uložený v mezipaměti souboru, se můžou dostat zastaralý obsah.

Použití tokenů změn ve scénáři ukládání souborů do mezipaměti brání přítomnosti zastaralého obsahu souboru v mezipaměti. Ukázková aplikace demonstruje implementaci přístupu.

Ukázka používá GetFileContent :

  • Vrátí obsah souboru.
  • Implementujte algoritmus opakování s exponenciálním zpětným vypnutím, aby zahrnoval případy, kdy problém s přístupem k souboru dočasně zpožďuje čtení obsahu souboru.

Utilities/Utilities.cs:

public async static Task<string> GetFileContent(string filePath)
{
    var runCount = 1;

    while(runCount < 4)
    {
        try
        {
            if (File.Exists(filePath))
            {
                using (var fileStreamReader = File.OpenText(filePath))
                {
                    return await fileStreamReader.ReadToEndAsync();
                }
            }
            else 
            {
                throw new FileNotFoundException();
            }
        }
        catch (IOException ex)
        {
            if (runCount == 3)
            {
                throw;
            }

            Thread.Sleep(TimeSpan.FromSeconds(Math.Pow(2, runCount)));
            runCount++;
        }
    }

    return null;
}

Vytvoří se a FileService zpracuje vyhledávání souborů uložených v mezipaměti. Volání GetFileContent metody služby se pokusí získat obsah souboru z mezipaměti v paměti a vrátit ho volajícímu (Services/FileService.cs).

Pokud se obsah uložený v mezipaměti pomocí klíče mezipaměti nenajde, provede se následující akce:

  1. Obsah souboru je získán pomocí GetFileContent.
  2. Token změny se získá od zprostředkovatele souborů pomocí IFileProviders.Watch. Zpětné volání tokenu se aktivuje při změně souboru.
  3. Obsah souboru se ukládá do mezipaměti s posunutým obdobím vypršení platnosti . Token změny je připojen k MemoryCacheEntryExtensions.AddExpirationToken k vyřazení položky mezipaměti, pokud se soubor změní v mezipaměti.

V následujícím příkladu jsou soubory uložené v kořenovém adresáři obsahu aplikace. IWebHostEnvironment.ContentRootFileProvider slouží k získání IFileProvider bodu na aplikaci IWebHostEnvironment.ContentRootPath. Získá se filePath pomocí IFileInfo.PhysicalPath.

public class FileService
{
    private readonly IMemoryCache _cache;
    private readonly IFileProvider _fileProvider;
    private List<string> _tokens = new List<string>();

    public FileService(IMemoryCache cache, IWebHostEnvironment env)
    {
        _cache = cache;
        _fileProvider = env.ContentRootFileProvider;
    }

    public async Task<string> GetFileContents(string fileName)
    {
        var filePath = _fileProvider.GetFileInfo(fileName).PhysicalPath;
        string fileContent;

        // Try to obtain the file contents from the cache.
        if (_cache.TryGetValue(filePath, out fileContent))
        {
            return fileContent;
        }

        // The cache doesn't have the entry, so obtain the file 
        // contents from the file itself.
        fileContent = await GetFileContent(filePath);

        if (fileContent != null)
        {
            // Obtain a change token from the file provider whose
            // callback is triggered when the file is modified.
            var changeToken = _fileProvider.Watch(fileName);

            // Configure the cache entry options for a five minute
            // sliding expiration and use the change token to
            // expire the file in the cache if the file is
            // modified.
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(5))
                .AddExpirationToken(changeToken);

            // Put the file contents into the cache.
            _cache.Set(filePath, fileContent, cacheEntryOptions);

            return fileContent;
        }

        return string.Empty;
    }
}

Je FileService zaregistrovaný v kontejneru služby spolu se službou ukládání do mezipaměti paměti.

V Startup.ConfigureServices:

services.AddMemoryCache();
services.AddSingleton<FileService>();

Stránkový model načte obsah souboru pomocí služby.

V metodě indexové stránky OnGet (Pages/Index.cshtml.cs):

var fileContent = await _fileService.GetFileContents("poem.txt");

CompositeChangeToken – třída

Pro reprezentaci jedné nebo více IChangeToken instancí v jednom objektu použijte CompositeChangeToken třídu.

var firstCancellationTokenSource = new CancellationTokenSource();
var secondCancellationTokenSource = new CancellationTokenSource();

var firstCancellationToken = firstCancellationTokenSource.Token;
var secondCancellationToken = secondCancellationTokenSource.Token;

var firstCancellationChangeToken = new CancellationChangeToken(firstCancellationToken);
var secondCancellationChangeToken = new CancellationChangeToken(secondCancellationToken);

var compositeChangeToken = 
    new CompositeChangeToken(
        new List<IChangeToken> 
        {
            firstCancellationChangeToken, 
            secondCancellationChangeToken
        });

HasChangedv sestavách true složeného tokenu, pokud je truenějaký reprezentovaný token HasChanged . ActiveChangeCallbacksv sestavách true složeného tokenu, pokud je truenějaký reprezentovaný token ActiveChangeCallbacks . Pokud dojde k více souběžných událostem změn, vyvolá se jednou zpětné volání složené změny.

Token změn je univerzální stavební blok nízké úrovně, který se používá ke sledování změn stavu.

Zobrazení nebo stažení ukázkového kódu (postup stažení)

IChangeToken – rozhraní

IChangeToken šíří oznámení, že došlo ke změně. IChangeToken se nachází v Microsoft.Extensions.Primitives oboru názvů. Pro aplikace, které nepoužívají metabalík Microsoft.AspNetCore.App, vytvořte odkaz na balíček NuGet Microsoft.Extensions.Primitives .

IChangeToken má dvě vlastnosti:

  • ActiveChangeCallbacks označuje, jestli token proaktivně vyvolává zpětná volání. Pokud ActiveChangedCallbacks je nastavená hodnota false, zpětné volání se nikdy nevolá a aplikace se musí dotazovat HasChanged na změny. Token je také možné nikdy zrušit, pokud nedojde k žádným změnám nebo se základní naslouchací proces změn odstraní nebo zakáže.
  • HasChanged obdrží hodnotu, která označuje, jestli došlo ke změně.

Rozhraní IChangeToken zahrnuje RegisterChangeCallback(Action<Object>, Object), která registruje zpětné volání, které je vyvoláno při změně tokenu. HasChanged musí být nastavena před vyvolání zpětného volání.

ChangeToken – třída

ChangeToken je statická třída používaná k šíření oznámení, že došlo ke změně. ChangeToken se nachází v Microsoft.Extensions.Primitives oboru názvů. Pro aplikace, které nepoužívají metabalík Microsoft.AspNetCore.App, vytvořte odkaz na balíček NuGet Microsoft.Extensions.Primitives .

Metoda ChangeToken.OnChange(Func<IChangeToken>, Action) zaregistruje Action volání při každé změně tokenu:

  • Func<IChangeToken> vytvoří token.
  • Action je volána při změně tokenu.

ChangeToken.OnChange <TState>(Func<IChangeToken>, Action<TState, TState>) přetížení přebírá další TState parametr, který je předán do příjemce Actiontokenu .

OnChange vrátí hodnotu IDisposable. Volání Dispose zastaví naslouchání tokenu dalším změnám a uvolní prostředky tokenu.

Příklad použití tokenů změn v ASP.NET Core

Tokeny změn se používají v hlavních oblastech ASP.NET Core k monitorování změn objektů:

  • Pro monitorování změn souborů IFileProviderWatch metoda vytvoří IChangeToken pro zadané soubory nebo složku, které se mají sledovat.
  • IChangeToken tokeny lze přidat do položek mezipaměti, aby se při změně aktivovaly vyřazení mezipaměti.
  • U TOptions změn má výchozí OptionsMonitor<TOptions> implementace IOptionsMonitor<TOptions> přetížení, které přijímá jednu nebo více IOptionsChangeTokenSource<TOptions> instancí. Každá instance vrátí metodu IChangeToken pro registraci zpětného volání oznámení o změnách pro sledování změn možností.

Monitorování změn konfigurace

Ve výchozím nastavení ASP.NET šablony Core používají konfigurační soubory JSON (appsettings.jsonappsettings.Development.jsonaappsettings.Production.json) k načtení nastavení konfigurace aplikace.

Tyto soubory se konfigurují pomocí metody ConfigurationBuilder rozšíření AddJsonFile(IConfigurationBuilder, String, Boolean, Boolean), která přijímá reloadOnChange parametr. reloadOnChange označuje, jestli by se při změně souboru měla znovu načíst konfigurace. Toto nastavení se zobrazí v WebHost metodě CreateDefaultBuilderusnadnění:

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, 
          reloadOnChange: true);

Konfigurace založená na souborech je reprezentována .FileConfigurationSource FileConfigurationSource používá IFileProvider k monitorování souborů.

Ve výchozím nastavení IFileMonitor je poskytována nástrojem PhysicalFileProvider, který používá FileSystemWatcher ke sledování změn konfiguračního souboru.

Ukázková aplikace ukazuje dvě implementace pro monitorování změn konfigurace. Pokud se některý ze appsettings souborů změní, spustí se v obou implementacích monitorování souborů vlastní kód – ukázková aplikace zapíše zprávu do konzoly.

Konfigurační soubor FileSystemWatcher může aktivovat více zpětných volání tokenů pro změnu jednoho konfiguračního souboru. Aby se zajistilo, že se vlastní kód spustí jenom jednou, když se aktivuje více zpětných volání tokenů, zkontroluje implementace ukázky hodnoty hash souboru. Ukázka používá hashování souborů SHA1. Opakování se implementuje s exponenciálním zpětným vypnutím.

Utilities/Utilities.cs:

public static byte[] ComputeHash(string filePath)
{
    var runCount = 1;

    while(runCount < 4)
    {
        try
        {
            if (File.Exists(filePath))
            {
                using (var fs = File.OpenRead(filePath))
                {
                    return System.Security.Cryptography.SHA1
                        .Create().ComputeHash(fs);
                }
            }
            else 
            {
                throw new FileNotFoundException();
            }
        }
        catch (IOException ex)
        {
            if (runCount == 3)
            {
                throw;
            }

            Thread.Sleep(TimeSpan.FromSeconds(Math.Pow(2, runCount)));
            runCount++;
        }
    }

    return new byte[20];
}

Jednoduchý token změny spuštění

Zaregistrujte zpětné volání příjemce Action tokenu pro oznámení o změnách do tokenu opětovného načtení konfigurace.

V Startup.Configure:

ChangeToken.OnChange(
    () => config.GetReloadToken(),
    (state) => InvokeChanged(state),
    env);

config.GetReloadToken() poskytuje token. Zpětné volání je InvokeChanged metoda:

private void InvokeChanged(IHostingEnvironment env)
{
    byte[] appsettingsHash = ComputeHash("appSettings.json");
    byte[] appsettingsEnvHash = 
        ComputeHash($"appSettings.{env.EnvironmentName}.json");

    if (!_appsettingsHash.SequenceEqual(appsettingsHash) || 
        !_appsettingsEnvHash.SequenceEqual(appsettingsEnvHash))
    {
        _appsettingsHash = appsettingsHash;
        _appsettingsEnvHash = appsettingsEnvHash;

        WriteConsole("Configuration changed (Simple Startup Change Token)");
    }
}

Zpětné state volání se používá k předání IHostingEnvironment, což je užitečné pro určení správného appsettings konfiguračního souboru pro monitorování (například appsettings.Development.json v prostředí pro vývoj). Hodnoty hash souborů se používají k tomu, aby příkaz neběžil WriteConsole několikrát kvůli více zpětným voláním tokenů, když se konfigurační soubor změnil pouze jednou.

Tento systém běží, pokud je aplikace spuštěná a uživatel ji nemůže zakázat.

Monitorování změn konfigurace jako služby

Ukázka implementuje:

  • Základní monitorování spouštěcích tokenů
  • Monitorování jako služba
  • Mechanismus pro povolení a zakázání monitorování.

Ukázka vytvoří IConfigurationMonitor rozhraní.

Extensions/ConfigurationMonitor.cs:

public interface IConfigurationMonitor
{
    bool MonitoringEnabled { get; set; }
    string CurrentState { get; set; }
}

Konstruktor implementované třídy , ConfigurationMonitorzaregistruje zpětné volání pro oznámení o změnách:

public ConfigurationMonitor(IConfiguration config, IHostingEnvironment env)
{
    _env = env;

    ChangeToken.OnChange<IConfigurationMonitor>(
        () => config.GetReloadToken(),
        InvokeChanged,
        this);
}

public bool MonitoringEnabled { get; set; } = false;
public string CurrentState { get; set; } = "Not monitoring";

config.GetReloadToken() poskytuje token. InvokeChanged je metoda zpětného volání. V state této instanci je odkaz na IConfigurationMonitor instanci, která se používá pro přístup ke stavu monitorování. Používají se dvě vlastnosti:

  • MonitoringEnabled: Označuje, jestli má zpětné volání spustit vlastní kód.
  • CurrentState: Popisuje aktuální stav monitorování pro použití v uživatelském rozhraní.

Metoda InvokeChanged se podobá dřívějšímu přístupu s tím rozdílem, že:

  • Nespouští jeho kód, pokud MonitoringEnabled není true.
  • Vypíše aktuální výsledek state výstupu WriteConsole .
private void InvokeChanged(IConfigurationMonitor state)
{
    if (MonitoringEnabled)
    {
        byte[] appsettingsHash = ComputeHash("appSettings.json");
        byte[] appsettingsEnvHash = 
            ComputeHash($"appSettings.{_env.EnvironmentName}.json");

        if (!_appsettingsHash.SequenceEqual(appsettingsHash) || 
            !_appsettingsEnvHash.SequenceEqual(appsettingsEnvHash))
        {
            string message = $"State updated at {DateTime.Now}";
          

            _appsettingsHash = appsettingsHash;
            _appsettingsEnvHash = appsettingsEnvHash;

            WriteConsole("Configuration changed (ConfigurationMonitor Class) " +
                $"{message}, state:{state.CurrentState}");
        }
    }
}

Instance ConfigurationMonitor je zaregistrovaná jako služba v Startup.ConfigureServices:

services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();

Stránka Index nabízí uživateli kontrolu nad monitorováním konfigurace. Instance IConfigurationMonitor je vložena IndexModeldo .

Pages/Index.cshtml.cs:

public IndexModel(
    IConfiguration config, 
    IConfigurationMonitor monitor, 
    FileService fileService)
{
    _config = config;
    _monitor = monitor;
    _fileService = fileService;
}

Monitorování konfigurace (_monitor) slouží k povolení nebo zakázání monitorování a nastavení aktuálního stavu pro zpětnou vazbu uživatelského rozhraní:

public IActionResult OnPostStartMonitoring()
{
    _monitor.MonitoringEnabled = true;
    _monitor.CurrentState = "Monitoring!";

    return RedirectToPage();
}

public IActionResult OnPostStopMonitoring()
{
    _monitor.MonitoringEnabled = false;
    _monitor.CurrentState = "Not monitoring";

    return RedirectToPage();
}

Po OnPostStartMonitoring aktivaci se povolí monitorování a aktuální stav se vymaže. Když OnPostStopMonitoring se aktivuje, monitorování je zakázané a stav je nastavený tak, aby odrážel, že se monitorování neprojevuje.

Tlačítka v uživatelském rozhraní umožňují a zakazují monitorování.

Pages/Index.cshtml:

<button class="btn btn-success" asp-page-handler="StartMonitoring">
    Start Monitoring
</button>

<button class="btn btn-danger" asp-page-handler="StopMonitoring">
    Stop Monitoring
</button>

Monitorování změn souborů uložených v mezipaměti

Obsah souboru lze ukládat do mezipaměti pomocí .IMemoryCache Ukládání do mezipaměti je popsáno v tématu Mezipaměť v paměti . Bez provedení dalších kroků, jako je implementace popsaná níže, se zastaralá (zastaralá) data vrátí z mezipaměti, pokud se zdrojová data změní.

Například při obnovování období vypršení platnosti se stavem zdrojového souboru uloženého v mezipaměti vede k zastaralým datům souborů uložených v mezipaměti. Každá žádost o data prodlužuje dobu vypršení platnosti, ale soubor se nikdy znovu nenačte do mezipaměti. Na všechny funkce aplikace, které používají obsah uložený v mezipaměti souboru, se můžou dostat zastaralý obsah.

Použití tokenů změn ve scénáři ukládání souborů do mezipaměti brání přítomnosti zastaralého obsahu souboru v mezipaměti. Ukázková aplikace demonstruje implementaci přístupu.

Ukázka používá GetFileContent :

  • Vrátí obsah souboru.
  • Implementujte algoritmus opakování s exponenciálním zpětným vypnutím, aby zahrnoval případy, kdy problém s přístupem k souboru dočasně zpožďuje čtení obsahu souboru.

Utilities/Utilities.cs:

public async static Task<string> GetFileContent(string filePath)
{
    var runCount = 1;

    while(runCount < 4)
    {
        try
        {
            if (File.Exists(filePath))
            {
                using (var fileStreamReader = File.OpenText(filePath))
                {
                    return await fileStreamReader.ReadToEndAsync();
                }
            }
            else 
            {
                throw new FileNotFoundException();
            }
        }
        catch (IOException ex)
        {
            if (runCount == 3 || ex.HResult != -2147024864)
            {
                throw;
            }
            else
            {
                await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, runCount)));
                runCount++;
            }
        }
    }

    return null;
}

Vytvoří se a FileService zpracuje vyhledávání souborů uložených v mezipaměti. Volání GetFileContent metody služby se pokusí získat obsah souboru z mezipaměti v paměti a vrátit ho volajícímu (Services/FileService.cs).

Pokud se obsah uložený v mezipaměti pomocí klíče mezipaměti nenajde, provede se následující akce:

  1. Obsah souboru je získán pomocí GetFileContent.
  2. Token změny se získá od zprostředkovatele souborů pomocí IFileProviders.Watch. Zpětné volání tokenu se aktivuje při změně souboru.
  3. Obsah souboru se ukládá do mezipaměti s posunutým obdobím vypršení platnosti . Token změny je připojen k MemoryCacheEntryExtensions.AddExpirationToken k vyřazení položky mezipaměti, pokud se soubor změní v mezipaměti.

V následujícím příkladu jsou soubory uložené v kořenovém adresáři obsahu aplikace. IHostingEnvironment.ContentRootFileProvider se používá k získání IFileProvider bodu na aplikaci ContentRootPath. Získá se filePath pomocí IFileInfo.PhysicalPath.

public class FileService
{
    private readonly IMemoryCache _cache;
    private readonly IFileProvider _fileProvider;
    private List<string> _tokens = new List<string>();

    public FileService(IMemoryCache cache, IHostingEnvironment env)
    {
        _cache = cache;
        _fileProvider = env.ContentRootFileProvider;
    }

    public async Task<string> GetFileContents(string fileName)
    {
        var filePath = _fileProvider.GetFileInfo(fileName).PhysicalPath;
        string fileContent;

        // Try to obtain the file contents from the cache.
        if (_cache.TryGetValue(filePath, out fileContent))
        {
            return fileContent;
        }

        // The cache doesn't have the entry, so obtain the file 
        // contents from the file itself.
        fileContent = await GetFileContent(filePath);

        if (fileContent != null)
        {
            // Obtain a change token from the file provider whose
            // callback is triggered when the file is modified.
            var changeToken = _fileProvider.Watch(fileName);

            // Configure the cache entry options for a five minute
            // sliding expiration and use the change token to
            // expire the file in the cache if the file is
            // modified.
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(5))
                .AddExpirationToken(changeToken);

            // Put the file contents into the cache.
            _cache.Set(filePath, fileContent, cacheEntryOptions);

            return fileContent;
        }

        return string.Empty;
    }
}

Je FileService zaregistrovaný v kontejneru služby spolu se službou ukládání do mezipaměti paměti.

V Startup.ConfigureServices:

services.AddMemoryCache();
services.AddSingleton<FileService>();

Stránkový model načte obsah souboru pomocí služby.

V metodě indexové stránky OnGet (Pages/Index.cshtml.cs):

var fileContent = await _fileService.GetFileContents("poem.txt");

CompositeChangeToken – třída

Pro reprezentaci jedné nebo více IChangeToken instancí v jednom objektu použijte CompositeChangeToken třídu.

var firstCancellationTokenSource = new CancellationTokenSource();
var secondCancellationTokenSource = new CancellationTokenSource();

var firstCancellationToken = firstCancellationTokenSource.Token;
var secondCancellationToken = secondCancellationTokenSource.Token;

var firstCancellationChangeToken = new CancellationChangeToken(firstCancellationToken);
var secondCancellationChangeToken = new CancellationChangeToken(secondCancellationToken);

var compositeChangeToken = 
    new CompositeChangeToken(
        new List<IChangeToken> 
        {
            firstCancellationChangeToken, 
            secondCancellationChangeToken
        });

HasChangedv sestavách true složeného tokenu, pokud je truenějaký reprezentovaný token HasChanged . ActiveChangeCallbacksv sestavách true složeného tokenu, pokud je truenějaký reprezentovaný token ActiveChangeCallbacks . Pokud dojde k více souběžných událostem změn, vyvolá se jednou zpětné volání složené změny.

Další materiály