Bagikan melalui


Mendeteksi perubahan dengan token perubahan di ASP.NET Core

Token perubahan adalah blok penyusun tingkat rendah tujuan umum yang digunakan untuk melacak perubahan status.

Melihat atau mengunduh kode sampel (cara mengunduh)

Antarmuka IChangeToken

IChangeToken menyebarluaskan pemberitahuan bahwa telah terjadi perubahan. IChangeToken berada di Microsoft.Extensions.Primitives namespace layanan. Paket NuGet Microsoft.Extensions.Primitives secara implisit disediakan untuk aplikasi ASP.NET Core.

IChangeToken memiliki dua properti:

  • ActiveChangeCallbacks menunjukkan apakah token secara proaktif menaikkan panggilan balik. Jika ActiveChangedCallbacks diatur ke false, panggilan balik tidak pernah dipanggil, dan aplikasi harus melakukan polling HasChanged untuk perubahan. Token juga dimungkinkan untuk tidak pernah dibatalkan jika tidak ada perubahan yang terjadi atau pendengar perubahan yang mendasar dibuang atau dinonaktifkan.
  • HasChanged menerima nilai yang menunjukkan apakah perubahan telah terjadi.

Antarmuka IChangeToken mencakup metode RegisterChangeCallback(Action<Object>, Object), yang mendaftarkan panggilan balik yang dipanggil ketika token telah berubah. HasChanged harus diatur sebelum panggilan balik dipanggil.

Kelas ChangeToken

ChangeToken adalah kelas statis yang digunakan untuk menyebarluaskan pemberitahuan bahwa perubahan telah terjadi. ChangeToken berada di Microsoft.Extensions.Primitives namespace layanan. Paket NuGet Microsoft.Extensions.Primitives secara implisit disediakan untuk aplikasi ASP.NET Core.

Metode ChangeToken.OnChange(Func<IChangeToken>, Action) mendaftarkan Action untuk memanggil setiap kali token berubah:

  • Func<IChangeToken> menghasilkan token.
  • Action dipanggil ketika token berubah.

Overload ChangeToken.OnChange<TState>(Func<IChangeToken>, Action<TState>, TState) mengambil parameter tambahan TState yang diteruskan ke konsumen Actiontoken .

OnChangeIDisposablemengembalikan . Dispose Panggilan menghentikan token mendengarkan perubahan lebih lanjut dan merilis sumber daya token.

Contoh penggunaan token perubahan di ASP.NET Core

Token perubahan digunakan di area ASP.NET Core yang menonjol untuk memantau perubahan pada objek:

  • Untuk memantau perubahan pada file, IFileProviderWatch metode membuat IChangeToken untuk file atau folder yang ditentukan untuk ditonton.
  • IChangeToken token dapat ditambahkan ke entri cache untuk memicu pengeluaran cache saat perubahan.
  • Untuk TOptions perubahan, implementasi IOptionsMonitor<TOptions> default OptionsMonitor<TOptions> memiliki kelebihan beban yang menerima satu atau beberapa IOptionsChangeTokenSource<TOptions> instans. Setiap instans IChangeToken mengembalikan untuk mendaftarkan panggilan balik pemberitahuan perubahan untuk melacak perubahan opsi.

Memantau perubahan konfigurasi

Secara default, templat ASP.NET Core menggunakan JSfile konfigurasi ON (appsettings.json, appsettings.Development.json, dan appsettings.Production.json) untuk memuat pengaturan konfigurasi aplikasi.

File-file ini dikonfigurasi menggunakan metode ekstensi AddJsonFile(IConfigurationBuilder, String, Boolean, Boolean) yang ConfigurationBuilder menerima reloadOnChange parameter. reloadOnChange menunjukkan apakah konfigurasi harus dimuat ulang pada perubahan file. Pengaturan ini muncul dalam Host metode CreateDefaultBuilderkenyamanan :

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

Konfigurasi berbasis file diwakili oleh FileConfigurationSource. FileConfigurationSourceIFileProvider menggunakan untuk memantau file.

Secara default, IFileMonitor disediakan oleh PhysicalFileProvider, yang menggunakan FileSystemWatcher untuk memantau perubahan file konfigurasi.

Aplikasi sampel menunjukkan dua implementasi untuk memantau perubahan konfigurasi. Jika salah satu appsettings file berubah, kedua implementasi pemantauan file menjalankan kode kustom—aplikasi sampel menulis pesan ke konsol.

File FileSystemWatcher konfigurasi dapat memicu beberapa panggilan balik token untuk perubahan file konfigurasi tunggal. Untuk memastikan bahwa kode kustom hanya dijalankan sekali ketika beberapa panggilan balik token dipicu, implementasi sampel memeriksa hash file. Sampel menggunakan hashing file SHA1. Coba lagi diimplementasikan dengan back-off eksponensial.

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

Token perubahan startup sederhana

Daftarkan panggilan balik konsumen Action token untuk mengubah pemberitahuan ke token reload konfigurasi.

Di Startup.Configure:

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

config.GetReloadToken() menyediakan token. Panggilan balik adalah InvokeChanged metode:

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

Panggilan state balik digunakan untuk meneruskan IWebHostEnvironment, yang berguna untuk menentukan file konfigurasi yang benar appsettings untuk dipantau (misalnya, appsettings.Development.json ketika di lingkungan Pengembangan). Hash file digunakan untuk mencegah WriteConsole pernyataan berjalan beberapa kali karena beberapa panggilan balik token ketika file konfigurasi hanya berubah sekali.

Sistem ini berjalan selama aplikasi berjalan dan tidak dapat dinonaktifkan oleh pengguna.

Memantau perubahan konfigurasi sebagai layanan

Sampel mengimplementasikan:

  • Pemantauan token startup dasar.
  • Pemantauan sebagai layanan.
  • Mekanisme untuk mengaktifkan dan menonaktifkan pemantauan.

Sampel menetapkan IConfigurationMonitor antarmuka.

Extensions/ConfigurationMonitor.cs:

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

Konstruktor kelas yang diimplementasikan, ConfigurationMonitor, mendaftarkan panggilan balik untuk pemberitahuan perubahan:

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() memasok token. InvokeChanged adalah metode panggilan balik. state Dalam instans ini adalah referensi ke IConfigurationMonitor instans yang digunakan untuk mengakses status pemantauan. Dua properti digunakan:

  • MonitoringEnabled: Menunjukkan apakah panggilan balik harus menjalankan kode kustomnya.
  • CurrentState: Menjelaskan status pemantauan saat ini untuk digunakan di UI.

Metode InvokeChanged ini mirip dengan pendekatan sebelumnya, kecuali:

  • Tidak menjalankan kodenya kecuali MonitoringEnabled adalah true.
  • Menghasilkan arus state dalam outputnya 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}");
        }
    }
}

Instans ConfigurationMonitor terdaftar sebagai layanan di Startup.ConfigureServices:

services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();

Halaman Indeks menawarkan kontrol pengguna atas pemantauan konfigurasi. Instans IConfigurationMonitor disuntikkan ke IndexModeldalam .

Pages/Index.cshtml.cs:

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

Monitor konfigurasi (_monitor) digunakan untuk mengaktifkan atau menonaktifkan pemantauan dan mengatur status saat ini untuk umpan balik UI:

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

    return RedirectToPage();
}

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

    return RedirectToPage();
}

Ketika OnPostStartMonitoring dipicu, pemantauan diaktifkan, dan status saat ini dibersihkan. Saat OnPostStopMonitoring dipicu, pemantauan dinonaktifkan, dan status diatur untuk mencerminkan bahwa pemantauan tidak terjadi.

Tombol di antarmuka pengguna mengaktifkan dan menonaktifkan pemantauan.

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>

Memantau perubahan file yang di-cache

Konten file dapat di-cache dalam memori menggunakan IMemoryCache. Penembolokan dalam memori dijelaskan dalam topik Cache dalam memori . Tanpa mengambil langkah tambahan, seperti implementasi yang dijelaskan di bawah ini, data basi (kedaluarsa) dikembalikan dari cache jika data sumber berubah.

Misalnya, tidak memperhitungkan status file sumber yang di-cache saat memperbarui periode kedaluwarsa geser menyebabkan data file cache kedaluwarsa. Setiap permintaan untuk data memperbarui periode kedaluwarsa geser, tetapi file tidak pernah dimuat ulang ke dalam cache. Fitur aplikasi apa pun yang menggunakan konten yang di-cache file mungkin tunduk pada penerimaan konten kedaluarsa.

Menggunakan token perubahan dalam skenario penembolokan file mencegah adanya konten file basi di cache. Aplikasi sampel menunjukkan implementasi pendekatan.

Sampel menggunakan GetFileContent untuk:

  • Mengembalikan konten file.
  • Terapkan algoritma coba lagi dengan back-off eksponensial untuk mencakup kasus di mana masalah akses file menunda sementara membaca konten file.

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

FileService dibuat untuk menangani pencarian file yang di-cache. Panggilan GetFileContent metode layanan mencoba mendapatkan konten file dari cache dalam memori dan mengembalikannya ke pemanggil (Services/FileService.cs).

Jika konten yang di-cache tidak ditemukan menggunakan kunci cache, tindakan berikut diambil:

  1. Konten file diperoleh menggunakan GetFileContent.
  2. Token perubahan diperoleh dari penyedia file dengan IFileProviders.Watch. Panggilan balik token dipicu saat file dimodifikasi.
  3. Konten file di-cache dengan periode kedaluwarsa geser. Token perubahan dilampirkan dengan MemoryCacheEntryExtensions.AddExpirationToken untuk mengeluarkan entri cache jika file berubah saat di-cache.

Dalam contoh berikut, file disimpan di akar konten aplikasi. IWebHostEnvironment.ContentRootFileProvider digunakan untuk mendapatkan IFileProvider penunjuk pada aplikasi IWebHostEnvironment.ContentRootPath. diperoleh filePath dengan 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;
    }
}

FileService terdaftar dalam kontainer layanan bersama dengan layanan penembolokan memori.

Di Startup.ConfigureServices:

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

Model halaman memuat konten file menggunakan layanan .

Dalam metode halaman OnGet Indeks (Pages/Index.cshtml.cs):

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

Kelas CompositeChangeToken

Untuk mewakili satu atau beberapa IChangeToken instans dalam satu objek, gunakan CompositeChangeToken kelas .

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 pada laporan true token komposit jika ada token HasChanged yang diwakili adalah true. ActiveChangeCallbacks pada laporan true token komposit jika ada token ActiveChangeCallbacks yang diwakili adalah true. Jika beberapa peristiwa perubahan bersamaan terjadi, panggilan balik perubahan komposit dipanggil satu kali.

Token perubahan adalah blok penyusun tingkat rendah tujuan umum yang digunakan untuk melacak perubahan status.

Melihat atau mengunduh kode sampel (cara mengunduh)

Antarmuka IChangeToken

IChangeToken menyebarluaskan pemberitahuan bahwa telah terjadi perubahan. IChangeToken berada di Microsoft.Extensions.Primitives namespace layanan. Untuk aplikasi yang tidak menggunakan metapackage Microsoft.AspNetCore.App, buat referensi paket untuk paket NuGet Microsoft.Extensions.Primitives .

IChangeToken memiliki dua properti:

  • ActiveChangeCallbacks menunjukkan apakah token secara proaktif menaikkan panggilan balik. Jika ActiveChangedCallbacks diatur ke false, panggilan balik tidak pernah dipanggil, dan aplikasi harus melakukan polling HasChanged untuk perubahan. Token juga dimungkinkan untuk tidak pernah dibatalkan jika tidak ada perubahan yang terjadi atau pendengar perubahan yang mendasar dibuang atau dinonaktifkan.
  • HasChanged menerima nilai yang menunjukkan apakah perubahan telah terjadi.

Antarmuka IChangeToken mencakup metode RegisterChangeCallback(Action<Object>, Object), yang mendaftarkan panggilan balik yang dipanggil ketika token telah berubah. HasChanged harus diatur sebelum panggilan balik dipanggil.

Kelas ChangeToken

ChangeToken adalah kelas statis yang digunakan untuk menyebarluaskan pemberitahuan bahwa perubahan telah terjadi. ChangeToken berada di Microsoft.Extensions.Primitives namespace layanan. Untuk aplikasi yang tidak menggunakan metapackage Microsoft.AspNetCore.App, buat referensi paket untuk paket NuGet Microsoft.Extensions.Primitives .

Metode ChangeToken.OnChange(Func<IChangeToken>, Action) mendaftarkan Action untuk memanggil setiap kali token berubah:

  • Func<IChangeToken> menghasilkan token.
  • Action dipanggil ketika token berubah.

Overload ChangeToken.OnChange<TState>(Func<IChangeToken>, Action<TState>, TState) mengambil parameter tambahan TState yang diteruskan ke konsumen Actiontoken .

OnChangeIDisposablemengembalikan . Dispose Panggilan menghentikan token mendengarkan perubahan lebih lanjut dan merilis sumber daya token.

Contoh penggunaan token perubahan di ASP.NET Core

Token perubahan digunakan di area ASP.NET Core yang menonjol untuk memantau perubahan pada objek:

  • Untuk memantau perubahan pada file, IFileProviderWatch metode membuat IChangeToken untuk file atau folder yang ditentukan untuk ditonton.
  • IChangeToken token dapat ditambahkan ke entri cache untuk memicu pengeluaran cache saat perubahan.
  • Untuk TOptions perubahan, implementasi IOptionsMonitor<TOptions> default OptionsMonitor<TOptions> memiliki kelebihan beban yang menerima satu atau beberapa IOptionsChangeTokenSource<TOptions> instans. Setiap instans IChangeToken mengembalikan untuk mendaftarkan panggilan balik pemberitahuan perubahan untuk melacak perubahan opsi.

Memantau perubahan konfigurasi

Secara default, templat ASP.NET Core menggunakan JSfile konfigurasi ON (appsettings.json, appsettings.Development.json, dan appsettings.Production.json) untuk memuat pengaturan konfigurasi aplikasi.

File-file ini dikonfigurasi menggunakan metode ekstensi AddJsonFile(IConfigurationBuilder, String, Boolean, Boolean) yang ConfigurationBuilder menerima reloadOnChange parameter. reloadOnChange menunjukkan apakah konfigurasi harus dimuat ulang pada perubahan file. Pengaturan ini muncul dalam WebHost metode CreateDefaultBuilderkenyamanan :

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

Konfigurasi berbasis file diwakili oleh FileConfigurationSource. FileConfigurationSourceIFileProvider menggunakan untuk memantau file.

Secara default, IFileMonitor disediakan oleh PhysicalFileProvider, yang menggunakan FileSystemWatcher untuk memantau perubahan file konfigurasi.

Aplikasi sampel menunjukkan dua implementasi untuk memantau perubahan konfigurasi. Jika salah satu appsettings file berubah, kedua implementasi pemantauan file menjalankan kode kustom—aplikasi sampel menulis pesan ke konsol.

File FileSystemWatcher konfigurasi dapat memicu beberapa panggilan balik token untuk perubahan file konfigurasi tunggal. Untuk memastikan bahwa kode kustom hanya dijalankan sekali ketika beberapa panggilan balik token dipicu, implementasi sampel memeriksa hash file. Sampel menggunakan hashing file SHA1. Coba lagi diimplementasikan dengan back-off eksponensial.

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

Token perubahan startup sederhana

Daftarkan panggilan balik konsumen Action token untuk mengubah pemberitahuan ke token reload konfigurasi.

Di Startup.Configure:

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

config.GetReloadToken() menyediakan token. Panggilan balik adalah InvokeChanged metode:

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

Panggilan state balik digunakan untuk meneruskan IHostingEnvironment, yang berguna untuk menentukan file konfigurasi yang benar appsettings untuk dipantau (misalnya, appsettings.Development.json ketika di lingkungan Pengembangan). Hash file digunakan untuk mencegah WriteConsole pernyataan berjalan beberapa kali karena beberapa panggilan balik token ketika file konfigurasi hanya berubah sekali.

Sistem ini berjalan selama aplikasi berjalan dan tidak dapat dinonaktifkan oleh pengguna.

Memantau perubahan konfigurasi sebagai layanan

Sampel mengimplementasikan:

  • Pemantauan token startup dasar.
  • Pemantauan sebagai layanan.
  • Mekanisme untuk mengaktifkan dan menonaktifkan pemantauan.

Sampel menetapkan IConfigurationMonitor antarmuka.

Extensions/ConfigurationMonitor.cs:

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

Konstruktor kelas yang diimplementasikan, ConfigurationMonitor, mendaftarkan panggilan balik untuk pemberitahuan perubahan:

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() memasok token. InvokeChanged adalah metode panggilan balik. state Dalam instans ini adalah referensi ke IConfigurationMonitor instans yang digunakan untuk mengakses status pemantauan. Dua properti digunakan:

  • MonitoringEnabled: Menunjukkan apakah panggilan balik harus menjalankan kode kustomnya.
  • CurrentState: Menjelaskan status pemantauan saat ini untuk digunakan di UI.

Metode InvokeChanged ini mirip dengan pendekatan sebelumnya, kecuali:

  • Tidak menjalankan kodenya kecuali MonitoringEnabled adalah true.
  • Menghasilkan arus state dalam outputnya 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}");
        }
    }
}

Instans ConfigurationMonitor terdaftar sebagai layanan di Startup.ConfigureServices:

services.AddSingleton<IConfigurationMonitor, ConfigurationMonitor>();

Halaman Indeks menawarkan kontrol pengguna atas pemantauan konfigurasi. Instans IConfigurationMonitor disuntikkan ke IndexModeldalam .

Pages/Index.cshtml.cs:

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

Monitor konfigurasi (_monitor) digunakan untuk mengaktifkan atau menonaktifkan pemantauan dan mengatur status saat ini untuk umpan balik UI:

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

    return RedirectToPage();
}

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

    return RedirectToPage();
}

Ketika OnPostStartMonitoring dipicu, pemantauan diaktifkan, dan status saat ini dibersihkan. Saat OnPostStopMonitoring dipicu, pemantauan dinonaktifkan, dan status diatur untuk mencerminkan bahwa pemantauan tidak terjadi.

Tombol di antarmuka pengguna mengaktifkan dan menonaktifkan pemantauan.

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>

Memantau perubahan file yang di-cache

Konten file dapat di-cache dalam memori menggunakan IMemoryCache. Penembolokan dalam memori dijelaskan dalam topik Cache dalam memori . Tanpa mengambil langkah tambahan, seperti implementasi yang dijelaskan di bawah ini, data basi (kedaluarsa) dikembalikan dari cache jika data sumber berubah.

Misalnya, tidak memperhitungkan status file sumber yang di-cache saat memperbarui periode kedaluwarsa geser menyebabkan data file cache kedaluwarsa. Setiap permintaan untuk data memperbarui periode kedaluwarsa geser, tetapi file tidak pernah dimuat ulang ke dalam cache. Fitur aplikasi apa pun yang menggunakan konten yang di-cache file mungkin tunduk pada penerimaan konten kedaluarsa.

Menggunakan token perubahan dalam skenario penembolokan file mencegah adanya konten file basi di cache. Aplikasi sampel menunjukkan implementasi pendekatan.

Sampel menggunakan GetFileContent untuk:

  • Mengembalikan konten file.
  • Terapkan algoritma coba lagi dengan back-off eksponensial untuk mencakup kasus di mana masalah akses file menunda sementara membaca konten file.

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

FileService dibuat untuk menangani pencarian file yang di-cache. Panggilan GetFileContent metode layanan mencoba mendapatkan konten file dari cache dalam memori dan mengembalikannya ke pemanggil (Services/FileService.cs).

Jika konten yang di-cache tidak ditemukan menggunakan kunci cache, tindakan berikut diambil:

  1. Konten file diperoleh menggunakan GetFileContent.
  2. Token perubahan diperoleh dari penyedia file dengan IFileProviders.Watch. Panggilan balik token dipicu saat file dimodifikasi.
  3. Konten file di-cache dengan periode kedaluwarsa geser. Token perubahan dilampirkan dengan MemoryCacheEntryExtensions.AddExpirationToken untuk mengeluarkan entri cache jika file berubah saat di-cache.

Dalam contoh berikut, file disimpan di akar konten aplikasi. IHostingEnvironment.ContentRootFileProvider digunakan untuk mendapatkan IFileProvider pointing pada aplikasi ContentRootPath. diperoleh filePath dengan 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;
    }
}

FileService terdaftar dalam kontainer layanan bersama dengan layanan penembolokan memori.

Di Startup.ConfigureServices:

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

Model halaman memuat konten file menggunakan layanan .

Dalam metode halaman OnGet Indeks (Pages/Index.cshtml.cs):

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

Kelas CompositeChangeToken

Untuk mewakili satu atau beberapa IChangeToken instans dalam satu objek, gunakan CompositeChangeToken kelas .

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 pada laporan true token komposit jika ada token HasChanged yang diwakili adalah true. ActiveChangeCallbacks pada laporan true token komposit jika ada token ActiveChangeCallbacks yang diwakili adalah true. Jika beberapa peristiwa perubahan bersamaan terjadi, panggilan balik perubahan komposit dipanggil satu kali.

Sumber Daya Tambahan: