Zjišťovat změny pomocí tokenů změn v ASP.NET Core

Token změn je stavební blok pro obecné účely, který se používá ke sledování změn stavu.

Zobrazit nebo stáhnout ukázkový kód (Jak stáhnout)

Rozhraní IChangeToken

IChangeToken šíří oznámení, že došlo ke změně. IChangeToken nachází se v Microsoft.Extensions.Primitives oboru názvů. balíček Microsoft. extensions. primitivs NuGet je implicitně k dispozici pro ASP.NET Core aplikace.

IChangeToken má dvě vlastnosti:

  • ActiveChangeCallbacks označuje, zda token proaktivně vyvolává zpětná volání. Pokud ActiveChangedCallbacks je nastaveno na false , zpětné volání se nikdy nevolá a aplikace se musí dotazovat HasChanged na změny. Je také možné, že token nikdy nebude zrušen, pokud nedojde k žádným změnám nebo pokud se podkladová naslouchací proces změny odstraní nebo zakáže.
  • HasChanged přijímá hodnotu, která indikuje, jestli došlo ke změně.

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

ChangeToken – třída

ChangeToken je statická třída, která se používá k šíření oznámení, ke kterým došlo ke změně. ChangeToken nachází se v Microsoft.Extensions.Primitives oboru názvů. balíček Microsoft. extensions. primitivs NuGet je implicitně k dispozici pro ASP.NET Core aplikace.

Metoda ChangeToken. při změně (Func <IChangeToken> , Action) zaregistruje, Action aby se volala při každé změně tokenu:

  • Func<IChangeToken> vytvoří token.
  • Action se volá, když se změní token.

Přetížení ChangeToken.-Change <TState> (Func <IChangeToken> , Action <TState> , TState) přebírá další TState parametr, který se předává do příjemce tokenu Action .

OnChange Vrátí IDisposable . Volání Dispose zastaví token z naslouchání pro další změny a uvolní prostředky tokenu.

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

změna tokenů se používá ve výrazně ASP.NET Core ke sledování změn objektů:

  • Pro sledování změn souborů IFileProvider Watch vytvoří metoda IChangeToken pro zadané soubory nebo složky, které chcete sledovat.
  • IChangeToken tokeny lze přidat do záznamů mezipaměti a aktivovat tak vyřazení mezipaměti při změně.
  • Pro TOptions změny, výchozí OptionsMonitor<TOptions> implementace pro IOptionsMonitor<TOptions> má přetížení, které přijímá jednu nebo více IOptionsChangeTokenSource<TOptions> instancí. Každá instance vrátí IChangeToken k registraci zpětného volání upozornění na změnu pro změny možností sledování.

Monitorování pro změny konfigurace

ve výchozím nastavení používají šablony ASP.NET Core ke načtení nastavení konfigurace aplikace konfigurační soubory JSON ( appsettings.json , appsettings.Development.jszapnuté a appsettings.Production.jszapnuté).

Tyto soubory jsou konfigurovány pomocí metody rozšíření AddJsonFile (IConfigurationBuilder, String, Boolean, Boolean) ConfigurationBuilder , která přijímá reloadOnChange parametr. reloadOnChange Určuje, zda má být při změnách souborů znovu načtena konfigurace. Toto nastavení se zobrazí v Host metodě usnadnění CreateDefaultBuilder :

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

Konfigurace na základě souborů je reprezentována pomocí FileConfigurationSource . FileConfigurationSourceIFileProviderNástroj používá k monitorování souborů.

Ve výchozím nastavení IFileMonitor je k dispozici pomocí PhysicalFileProvider , který FileSystemWatcher Nástroj používá ke sledování změn konfiguračního souboru.

Ukázková aplikace ukazuje dvě implementace pro sledování změn konfigurace. Pokud se některý ze souborů appSettings změní, obě implementace monitorování souborů spustí 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í tokenu pro jednu změnu konfiguračního souboru. Chcete-li zajistit, aby se vlastní kód spouštěl pouze jednou při spuštění více zpětných volání tokenu, implementace ukázky kontroluje hodnoty hash souborů. Ukázka používá algoritmus hash souborů SHA1. Opakování je implementováno pomocí exponenciálního zálohování. Opakování je k dispozici, protože může dojít k uzamčení souboru, které dočasně znemožňuje výpočet nového algoritmu hash v souboru.

Nástroje/nástroje. 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 || ex.HResult != -2147024864)
            {
                throw;
            }
            else
            {
                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 tokenu Action pro oznámení změn 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)");
    }
}

stateZpětné volání se používá k předání do IWebHostEnvironment , což je užitečné při určení správného konfiguračního souboru appSettings , který se má monitorovat (například appsettings.Development.jsv případě, kdy ve vývojovém prostředí). Hodnoty hash souborů se používají k zabránění WriteConsole spuštění příkazu vícekrát v důsledku zpětného volání s více tokeny, když je konfigurační soubor změněn pouze jednou.

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

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

Ukázka implementuje:

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

Ukázka vytvoří IConfigurationMonitor rozhraní.

Rozšíření/ConfigurationMonitor. cs:

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

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

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() dodává token. InvokeChanged je metoda zpětného volání. stateV 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: Určuje, zda zpětné volání má spustit vlastní kód.
  • CurrentState: Popisuje aktuální stav monitorování pro použití v uživatelském rozhraní.

InvokeChangedMetoda je podobná dřívějšímu přístupu, s tím rozdílem, že:

  • Nespustí svůj kód MonitoringEnabled , pokud není true .
  • Vypíše aktuální state výstup do WriteConsole výstupu.
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 registrovaná jako služba v Startup.ConfigureServices :

services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();

Stránka index nabízí uživatelský ovládací prvek pro monitorování konfigurace. Instance IConfigurationMonitor je vložena do IndexModel .

Pages/index. cshtml. cs:

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

Nástroj Configuration monitor ( _monitor ) se používá 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();
}

Když OnPostStartMonitoring se aktivuje, monitorování je povolené a aktuální stav se vymaže. Když OnPostStopMonitoring se aktivuje, monitorování se zakáže a stav se nastaví tak, aby odrážel, že monitorování se nevyskytuje.

Tlačítka v uživatelském rozhraní povolují 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>

Monitorovat změny souborů v mezipaměti

Obsah souboru může být uložen v paměti pomocí IMemoryCache . Mezipaměť v paměti je popsána v tématu mezipaměť v paměti . Bez provedení dalších kroků, jako je třeba implementace popsaná níže, se z mezipaměti vrátí zastaralé (zastaralé) údaje, pokud se změní zdrojová data.

Například neberoucí se v úvahu stav zdrojového souboru v mezipaměti při obnovení klouzavého období vypršení platnosti vede k zastaralým datům souborů v mezipaměti. Každý požadavek na data obnoví klouzavé období vypršení platnosti, ale soubor se nikdy znovu nenačte do mezipaměti. Všechny funkce aplikace, které používají obsah uložený v mezipaměti, podléhají možnému přijetí zastaralého obsahu.

Použití změnových tokenů ve scénáři ukládání souborů do mezipaměti zabraňuje přítomnosti zastaralého obsahu souborů v mezipaměti. Ukázková aplikace ukazuje implementaci přístupu.

Ukázka používá GetFileContent :

  • Vrátit obsah souboru
  • Implementujte algoritmus opakování s exponenciálním přechodem na případy, kde zámek souboru dočasně brání v čtení souboru.

Nástroje/nástroje. 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 FileService pro zpracování vyhledávání souborů uložených v mezipaměti. GetFileContentVolání metody služby se pokusí získat obsah souboru z mezipaměti v paměti a vrátit je volajícímu (Services/Souborová služba. cs).

Pokud obsah uložený v mezipaměti nebyl nalezen pomocí klíče mezipaměti, jsou provedeny následující akce:

  1. Obsah souboru se získá pomocí GetFileContent .
  2. Z poskytovatele souboru se získá token pro změnu pomocí IFileProviders. Watch. Zpětné volání tokenu se aktivuje, když se soubor změnil.
  3. Obsah souboru se ukládá do mezipaměti s klouzavým vypršením platnosti. Token změny se připojí k MemoryCacheEntryExtensions.AddExpirationToken, aby se položka mezipaměti vyřazena, pokud se soubor během ukládání do mezipaměti změní.

V následujícím příkladu jsou soubory uložené v kořenovém adresáři obsahu aplikace. IWebHostEnvironment.ContentRootFileProvider se používá k získání IFileProvider odkazování na adresu IWebHostEnvironment.ContentRootPath . Se filePath získá 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;
    }
}

Objekt FileService je zaregistrovaný v kontejneru služby společně se službou ukládání do mezipaměti.

V Startup.ConfigureServices:

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

Model stránky načte obsah souboru pomocí služby .

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

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

CompositeChangeToken – třída

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

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

HasChanged ve složeném tokenu se true hlásí, pokud je nějaký reprezentovaný token HasChanged true . ActiveChangeCallbacks ve složeném tokenu se true hlásí, pokud je nějaký reprezentovaný token ActiveChangeCallbacks true . Pokud dojde k více souběžně probíhajícím událostem změny, vyvolá se zpětné volání složených změn jednou.

Token změny je základní stavební blok pro obecné účely, který se používá ke sledování změn stavu.

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

IChangeToken – rozhraní

IChangeToken šíří oznámení, že došlo ke změně. IChangeToken se nachází v oboru Microsoft.Extensions.Primitives názvů . V případě aplikací, které Microsoft.AspNetCore.App balíček metapackage, vytvořte odkaz na balíček pro balíček NuGet Microsoft.Extensions.Primitives.

IChangeToken má dvě vlastnosti:

  • ActiveChangeCallbacks označuje, zda token proaktivně vyvolává zpětná volání. Pokud je nastavená na , zpětné volání se nikdy nevolalo a aplikace ActiveChangedCallbacks false se musí HasChanged dotazovat na změny. Token se také může nezrušovat, pokud nedojde k žádným změnám nebo dojde k uvolnění nebo zabloku základního naslouchacího procesu změn.
  • HasChanged přijímá hodnotu, která indikuje, jestli došlo ke změně.

Rozhraní IChangeToken zahrnuje metodu RegisterChangeCallback(Action <Object> , Object), která registruje zpětné volání, které se vyvolá při změně tokenu. HasChanged Před vyvoláním zpětného volání je nutné nastavit .

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 oboru Microsoft.Extensions.Primitives názvů . V případě aplikací, které Microsoft.AspNetCore.App balíček metapackage, vytvořte odkaz na balíček pro balíček NuGet Microsoft.Extensions.Primitives.

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

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

Přetížení ChangeToken.OnChange <TState> (Func <IChangeToken> , Action , <TState> TState) přebírá další parametr předaný TState spotřebiteli tokenu Action .

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

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

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

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

Monitorování změn konfigurace

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

Tyto soubory se konfiguruje pomocí rozšiřující metody AddJsonFile(IConfigurationBuilder, String, Boolean, Boolean), která ConfigurationBuilder přijímá reloadOnChange parametr. reloadOnChange určuje, jestli se má konfigurace při změnách souborů znovu načíst. Toto nastavení se zobrazí v WebHost metodě CreateDefaultBuilder convenience:

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

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

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

Ukázková aplikace předvede dvě implementace pro monitorování změn konfigurace. Pokud se některý ze souborů appsettings změní, obě implementace monitorování souborů spustí vlastní kód, vzorová aplikace — zapíše zprávu do konzoly.

Objekt konfiguračního souboru může FileSystemWatcher aktivovat několik zpětných volání tokenů pro jednu změnu 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ů, implementace ukázky zkontroluje hash souborů. Ukázka používá hashování souborů SHA1. Opakování se implementuje s exponenciálním omezením. Opakování je přítomné, protože může dojít k zamykání souborů, které dočasně brání výpočtu nové hodnoty hash souboru.

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 || ex.HResult != -2147024864)
            {
                throw;
            }
            else
            {
                Thread.Sleep(TimeSpan.FromSeconds(Math.Pow(2, runCount)));
                runCount++;
            }
        }
    }

    return new byte[20];
}

Token změny jednoduchého spuštění

Zaregistrujte zpětné volání příjemce Action tokenu pro oznámení změn na token 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é volání slouží k předání , což je užitečné pro určení správného konfiguračního souboru appsettings, který se má monitorovat (napříkladappsettings.Development.json, když ve state IHostingEnvironment vývojovém prostředí). Pomocí hash souborů lze zabránit vícenásobnému spuštění příkazu z důvodu několika zpětných volání tokenů, pokud se konfigurační soubor WriteConsole změnil pouze jednou.

Tento systém běží tak dlouho, dokud je aplikace spuštěná a uživatel ho 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í.

Rozšíření/ConfigurationMonitor.cs:

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

Konstruktor implementované třídy ConfigurationMonitor zaregistruje zpětné volání pro oznámení změn:

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() zadá token. InvokeChanged je metoda zpětného volání. V state tomto případě je odkazem na instanci, která se používá pro přístup ke stavu IConfigurationMonitor monitorování. Používají se dvě vlastnosti:

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

Metoda InvokeChanged je podobná předchozímu přístupu s tím rozdílem, že:

  • Nespouštěl svůj kód, pokud MonitoringEnabled není true .
  • Výstupem je aktuální state WriteConsole výstup.
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 je ConfigurationMonitor zaregistrovaná jako služba v : Startup.ConfigureServices

services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();

Stránka Index nabízí kontrolu uživatelů nad monitorováním konfigurace. Instance se IConfigurationMonitor injektuje do IndexModel .

Pages/Index.cshtml.cs:

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

Monitorování konfigurace ( ) slouží k povolení nebo zakázání monitorování a nastavení aktuálního stavu zpětné vazby _monitor 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();
}

Když OnPostStartMonitoring se aktivuje, monitorování je povolené a aktuální stav se vyškrtá. Když se aktivuje, monitorování je zakázané a stav je nastavený tak, aby odrážel, že k monitorování OnPostStopMonitoring ne dochází.

Tlačítka v uživatelském rozhraní povolte a zakažte 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 se může ukládat do mezipaměti v paměti pomocí IMemoryCache . Ukládání do mezipaměti v paměti je popsané v tématu Mezipaměť v paměti. Bez provedení dalších kroků, jako je například implementace popsaná níže, se zastaralá (zastaralá) data vrátí z mezipaměti, pokud se zdrojová data změní.

Například když při prodloužení klouzací doby vypršení platnosti nezohledníte stav zdrojového souboru uloženého v mezipaměti, dojde k tomu, že data souboru v mezipaměti jsou zastaralá. Každý požadavek na data prodlužuje klouzanou dobu vypršení platnosti, ale soubor se nikdy znovu nenačte do mezipaměti. Na všechny funkce aplikace, které používají obsah v mezipaměti souboru, může dostávat 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 předvede implementaci tohoto přístupu.

Ukázka GetFileContent používá:

  • Vrácení obsahu souboru
  • Implementujte algoritmus opakování s exponenciálním omezením, který pokryje případy, kdy zámek souboru dočasně brání čtení 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ří FileService se pro zpracování vyhledávání souborů uložených v mezipaměti. Volání metody služby se pokusí získat obsah souboru z mezipaměti v paměti a vrátit ho volajícímu GetFileContent (Services/FileService.cs).

Pokud se obsah v mezipaměti pomocí klíče mezipaměti nenašel, prochytá se následující akce:

  1. Obsah souboru se získá pomocí GetFileContent .
  2. Token změny se získá od poskytovatele souborů pomocí IFileProviders.Watch. Zpětné volání tokenu se aktivuje, když se soubor změnil.
  3. Obsah souboru se ukládá do mezipaměti s klouzavým vypršením platnosti. Token změny se připojí k MemoryCacheEntryExtensions.AddExpirationToken, aby se položka mezipaměti vyřazena, pokud se soubor během ukládání do mezipaměti změní.

V následujícím příkladu jsou soubory uložené v kořenovém adresáři obsahu aplikace. K získání odkazování na objekt aplikace se používá IHostingEnvironment.ContentRootFileProvider. IFileProvider ContentRootPath Se filePath získá 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;
    }
}

Objekt FileService je zaregistrovaný v kontejneru služby společně se službou ukládání do mezipaměti.

V Startup.ConfigureServices:

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

Model stránky načte obsah souboru pomocí služby .

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

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

CompositeChangeToken – třída

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

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

HasChanged ve složeném tokenu se true hlásí, pokud je nějaký reprezentovaný token HasChanged true . ActiveChangeCallbacks ve složeném tokenu se true hlásí, pokud je nějaký reprezentovaný token ActiveChangeCallbacks true . Pokud dojde k několika souběžně probíhajícím událostem změny, vyvolá se zpětné volání složených změn jednou.

Další materiály