CefSharpカスタムキャッシュの実装

CefSharpカスタムキャッシュの実装

CefSharpのキャッシュ機能を適切に活用することで、アプリケーションのパフォーマンスとユーザーエクスペリエンスを向上させ、ネットワークトラフィックとサーバー負荷を削減し、オフラインアクセスをサポートするなど、非常に便利な機能です。

最終更新 2023/04/25 11:36
沙漠尽头的狼
読了目安 10 分
カテゴリ
.NET
タグ
.NET C# CefSharp

皆さん、こんにちは。砂漠の果ての狼です。

前回は『C#でCefSharpを使ってウェブページを埋め込み、C#とJSの相互作用の例を紹介』を紹介しました。今回は、CefSharpのキャッシュ実装について説明します。まず、キャッシュを追加する利点を挙げます。

  1. ページ読み込みの高速化:CefSharpのキャッシュは、既に読み込まれたページやリソースをキャッシュします。ユーザーが同じページに再度アクセスする際に、キャッシュから直接読み込むことができ、ページやリソースを再ダウンロードして解析する必要がないため、ページの読み込み速度が向上します。
  2. ネットワークトラフィックの削減:キャッシュを使用することで、既にダウンロードされたリソースをキャッシュから直接読み取ることができるため、ネットワークトラフィックを削減できます。
  3. ユーザーエクスペリエンスの向上:キャッシュによりページ読み込み速度が向上するため、ユーザーはより迅速にページやリソースにアクセスでき、アプリケーションをより快適に使用できます。
  4. サーバー負荷の軽減:キャッシュを使用することで、既にダウンロードされたリソースをキャッシュから直接読み取ることができるため、サーバーの負荷を軽減できます。
  5. オフラインアクセス:既にダウンロードされたページやリソースをキャッシュしておけば、ユーザーがネットワークに接続できない場合でも、キャッシュからページやリソースを読み込むことができ、オフラインアクセスをサポートします。

つまり、キャッシュを使用することでアプリケーションのパフォーマンスとユーザーエクスペリエンスを向上させ、ネットワークトラフィックとサーバー負荷を削減し、オフラインアクセスをサポートできるため、非常に便利な機能です。

本記事のサンプル:GitHub

オフライン状態で、既にキャッシュされた百度百度翻訳Dotnet9トップページDotnet9概要の4ページを読み込むデモ:

次に、キャッシュの実装方法を説明します。

1. デフォルトキャッシュの実装

CefSharpのデフォルトキャッシュの実装方法は、Chromiumのキャッシュメカニズムに基づいています。Chromiumは、メモリキャッシュとディスクキャッシュの2種類のキャッシュを使用しています。

1.1. メモリキャッシュ

メモリキャッシュはLRU(Least Recently Used)アルゴリズムに基づくキャッシュで、最近アクセスされたページやリソースをキャッシュします。メモリキャッシュのサイズは制限されており、キャッシュが最大サイズに達すると、最も最近使用されていないページやリソースが削除されます。

メモリキャッシュは、CefSharp.WPFのAPIでは設定できません。具体的には、Chromiumはメモリ内にLRUキャッシュを維持し、最近アクセスされたウェブページデータを保存します。キャッシュスペースが不足すると、ChromiumはLRUアルゴリズムに従って最も最近使用されていないキャッシュデータを自動的にクリアし、新しいデータを保存するためのスペースを確保します。

CefSharp.WPFでは、Cef.GetGlobalRequestContext().ClearCacheAsync() メソッドを呼び出してメモリキャッシュ内のデータをクリアできます。このメソッドはすべてのキャッシュデータ(メモリキャッシュとディスクキャッシュを含む)をクリアします。メモリキャッシュのみをクリアしたい場合は、Cef.GetGlobalRequestContext().ClearCache(CefCacheType.MemoryCache) メソッドを呼び出します。

注意点として、メモリキャッシュはChromium自身が管理するため、そのサイズを直接制御することはできません。キャッシュサイズを制御する必要がある場合は、ディスクキャッシュのサイズを設定することで間接的に制御できます。

1.2. ディスクキャッシュ

ディスクキャッシュはファイルシステムに基づくキャッシュで、既にダウンロードされたページやリソースをキャッシュします。ディスクキャッシュのサイズも制限されており、キャッシュが最大サイズに達すると、最も古いページやリソースが削除されます。

CefSharp.WPFのディスクキャッシュは、CefSettingsCachePath プロパティを設定することで実現します。具体的には、以下のコードでディスクキャッシュのパスを設定できます。

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // CachePathは絶対パスである必要があります
        var settings = new CefSettings
        {
            CachePath = $"{AppDomain.CurrentDomain.BaseDirectory}DefaultCaches"
        };
        Cef.Initialize(settings);
    }
}

キャッシュディレクトリ構造は以下の通りです。

CachePath プロパティはディスクキャッシュのパス(絶対パス)を指定します。このプロパティを設定しない場合、Chromiumはキャッシュデータをデフォルトのパス(通常はユーザーディレクトリの AppData\Local\CefSharp ディレクトリ)に保存します。

注意点として、ディスクキャッシュのサイズはChromium自身によって制御されます。CacheControllerSetCacheLimit メソッドを使用して、キャッシュデータがディスク上で使用できる最大容量を制御できます。このメソッドはlong型のパラメータ(キャッシュデータの最大サイズ(バイト単位))を受け取ります。例えば、以下のコードはディスクキャッシュの最大サイズを100MBに設定します。

var cacheController = Cef.GetGlobalRequestContext().CacheController;
cacheController.SetCacheLimit(100 * 1024 * 1024); // 100MB

注意点として、ChromiumはLRUアルゴリズムに従って最も最近使用されていないキャッシュデータを自動的にクリアし、新しいデータを保存するためのスペースを確保します。そのため、キャッシュサイズを設定しても、すべてのデータがキャッシュされるとは限りません。ディスクキャッシュ内のデータをクリアするには、Cef.GetGlobalRequestContext().ClearCacheAsync() メソッドを呼び出します。

デフォルトのキャッシュについては、私はあまり研究していません。上記のコードと説明はChatGPTで検索したものです。カスタムキャッシュの実装を見ていきましょう。デフォルトキャッシュは単なる導入です。

2. カスタムキャッシュ

これが本記事で紹介する重点です。デフォルトキャッシュに比べて、『カスタムキャッシュ』には以下の利点があります。

  1. より柔軟:アプリケーションのニーズに合わせてキャッシュ戦略やキャッシュサイズを柔軟に設定でき、アプリケーションの要件をより適切に満たすことができます。
  2. より良いパフォーマンス:アプリケーションのニーズや特定のシナリオに合わせて設定でき、より良いパフォーマンスを得られます。デフォルトのキャッシュは特定のシナリオやアプリケーションの要件に適さない場合がありますが、カスタムキャッシュは必要に応じて調整でき、より良いパフォーマンスを実現できます。
  3. より良いセキュリティ:キャッシュに保存される内容やキャッシュのライフサイクルを制御できるため、ユーザーのプライバシーとセキュリティをより適切に保護できます。
  4. より制御可能:キャッシュの動作をより適切に制御できます。例えば、キャッシュクリアのタイミングやクリア戦略を制御でき、キャッシュ管理が容易になります。
  5. より良い互換性:さまざまなブラウザやデバイスに適応しやすくなります。デフォルトのキャッシュでは十分な互換性が得られない場合がありますが、カスタムキャッシュは必要に応じて調整でき、より良い互換性を提供できます。
  6. より効率的:システムリソースをより有効活用できます。例えば、より高速なストレージデバイスを使用してキャッシュを保存し、キャッシュの読み書き速度を向上させることができます。

まとめ:カスタムキャッシュは、より良いパフォーマンス、応答性、セキュリティ、互換性を提供し、アプリケーションの品質とユーザーエクスペリエンスを向上させます。平たく言えば、より『制御』が効くということです。

2.1. コード実装

デフォルトキャッシュのコードは先頭にコメントアウトしています。

2.1.1. リソースリクエストインターセプトハンドラの登録

まず、ChromiumWebBrowser コントロールを使用するコードビハインドで、リクエストインターセプトハンドラを登録します。CefBrowser はコントロール名、CefRequestHandlerc はハンドラです。

public TestCefCacheView()
{
    InitializeComponent();

    var handler = new CefRequestHandlerc();
    CefBrowser.RequestHandler = handler;
}

2.1.2. リクエストインターセプトハンドラ

CefSharpの IRequestHandler は、ブラウザが発行するリクエストを処理するためのインターフェースです。リクエストがサーバーに送信される前または後に処理を行うためのメソッドが定義されています。

IRequestHandler の実装クラスは、以下の用途に使用できます。

  1. リクエストのインターセプト:OnBeforeBrowse メソッドを実装してリクエストをインターセプトし、ブラウザの動作を制御できます。例えば、リクエストがサーバーに送信される前にリクエストのURLをチェックし、要件を満たさない場合はリクエストをキャンセルしたり、別のページにリダイレクトしたりできます。

  2. リクエストの変更:OnBeforeResourceLoad メソッドを実装してリクエストを変更できます。例えば、カスタムHTTPヘッダーを追加したり、リクエストのURLを変更したりできます。

  3. レスポンスの処理:OnResourceResponse メソッドを実装してサーバーから返されたレスポンスを処理できます。例えば、レスポンスのステータスコードや内容をチェックし、ページの読み込みを続行するかどうかを決定できます。

  4. キャッシュ制御:OnQuotaRequest メソッドを実装してキャッシュのサイズやクリア戦略を制御し、キャッシュの使用を最適化できます。

つまり、IRequestHandler の実装クラスは、ブラウザの動作を制御し、ネットワークリクエストとキャッシュの使用を最適化することで、アプリケーションのパフォーマンスとユーザーエクスペリエンスを向上させることができます。

私たちは IRequestHandler インターフェースを直接実装するのではなく、そのデフォルト実装クラスである RequestHandler を継承します。これにより、開発を簡略化できます(インターフェースを実装する場合は多数のメソッドを列挙する必要があります)。

GetResourceRequestHandler メソッドをオーバーライドし、このメソッド内で CefResourceRequestHandler インスタンスを返します。ページ内のリソースリクエスト時にこのメソッドが呼び出されます。

using CefSharp;
using CefSharp.Handler;

namespace WpfWithCefSharpCacheDemo.Caches;

internal class CefRequestHandlerc : RequestHandler
{
    protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame,
        IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
    {
        // 1リクエストにつき1つのCefResourceRequestHandlerを使用
        return new CefResourceRequestHandler();
    }
}

2.1.3. リソースリクエストインターセプタ

CefSharpでは、IResourceRequestHandler インターフェースはリソースリクエストを処理するためのもので、ブラウザが発行するリソースリクエスト(画像、CSS、JavaScriptなど)をインターセプトし、リソースリクエストの制御と最適化を実現します。

具体的には、IResourceRequestHandler インターフェースには、OnBeforeResourceLoadOnResourceResponse などのメソッドが定義されています。これらのメソッドは、リクエストのインターセプト、リクエストの変更、レスポンスの処理などに使用できます。例えば:

  1. OnBeforeResourceLoad:ブラウザがリソースをリクエストする前に呼び出され、リクエストの変更(カスタムHTTPヘッダーの追加、リクエストURLの変更など)に使用できます。

  2. OnResourceResponse:ブラウザがサーバーからレスポンスを受信した後に呼び出され、レスポンスの処理(ステータスコードや内容のチェック、ページ読み込みの継続判断など)に使用できます。

  3. OnResourceLoadComplete:リソースの読み込みが完了した後に呼び出され、リソース読み込み完了後の操作(リソースのローカルキャッシュへの保存など)に使用できます。

IResourceRequestHandler インターフェースを実装することで、リソースリクエストをインターセプトおよび最適化し、アプリケーションのパフォーマンスとユーザーエクスペリエンスを向上させることができます。

ここでも IResourceRequestHandler インターフェースを直接実装するのではなく、CefResourceRequestHandler クラスを定義し、そのインターフェースのデフォルト実装クラスである ResourceRequestHandler を継承します。

以下の CefResourceRequestHandler クラスでは:

  1. GetResourceHandler メソッド:リソースをキャッシュする必要があるかどうかを処理します。nullを返すとキャッシュされず、CefResourceHandler を返すとキャッシュが必要であることを意味します。このクラス内でクロスドメイン処理を行います。
  2. GetResourceResponseFilter メソッド:リソースキャッシュの操作クラス(リソースダウンロードの実装)を登録します。
  3. OnBeforeResourceLoad メソッド:このメソッド内で、ページにヘッダーパラメータを渡す処理を実装できます。
using System.Collections.Specialized;
using CefSharp;
using CefSharp.Handler;

namespace WpfWithCefSharpCacheDemo.Caches;

internal class CefResourceRequestHandler : ResourceRequestHandler
{
    private string _localCacheFilePath;

    private bool IsLocalCacheFileExist => System.IO.File.Exists(_localCacheFilePath);

    protected override IResourceHandler? GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser,
        IFrame frame, IRequest request)
    {
        try
        {
            _localCacheFilePath = CacheFileHelper.CalculateResourceFileName(request.Url, request.ResourceType);
            if (string.IsNullOrWhiteSpace(_localCacheFilePath))
            {
                return null;
            }
        }
        catch
        {
            return null;
        }

        if (!IsLocalCacheFileExist)
        {
            return null;
        }

        return new CefResourceHandler(_localCacheFilePath);
    }

    protected override IResponseFilter? GetResourceResponseFilter(IWebBrowser chromiumWebBrowser, IBrowser browser,
        IFrame frame,
        IRequest request, IResponse response)
    {
        return IsLocalCacheFileExist ? null : new CefResponseFilter { LocalCacheFilePath = _localCacheFilePath };
    }

    protected override CefReturnValue OnBeforeResourceLoad(IWebBrowser chromiumWebBrowser, IBrowser browser,
        IFrame frame, IRequest request,
        IRequestCallback callback)
    {
        var headers = new NameValueCollection(request.Headers);
        headers["Authorization"] = "Bearer xxxxxx.xxxxx.xxx";
        request.Headers = headers;

        return CefReturnValue.Continue;
    }
}

2.1.4. CefResourceHandler

CefSharpでは、IResourceHandler インターフェースはリソースを処理するためのもので、ブラウザが発行するリソースリクエストをインターセプトし、カスタムリソースコンテンツを返すことで、リソースの制御と最適化を実現します。

具体的には、IResourceHandler インターフェースには、ProcessRequestGetResponseHeadersReadResponse などのメソッドが定義されています。これらのメソッドは、リソースリクエストの処理、レスポンスヘッダー情報の取得、レスポンスコンテンツの読み取りなどに使用できます。例えば:

  1. ProcessRequest:ブラウザがリソースをリクエストするときに呼び出され、リソースリクエストの処理(ローカルキャッシュからのリソースコンテンツの読み取り、またはネットワークからのリソースコンテンツのダウンロード)に使用できます。

  2. GetResponseHeaders:ブラウザがリソースをリクエストするときに呼び出され、レスポンスヘッダー情報の取得(MIMEタイプの設定、キャッシュ戦略など)に使用できます。

  3. ReadResponse:ブラウザがリソースをリクエストするときに呼び出され、レスポンスコンテンツの読み取り(ローカルキャッシュからのリソースコンテンツの読み取り、またはネットワークからのリソースコンテンツのダウンロード)に使用できます。

IResourceHandler インターフェースを実装することで、リソースをカスタム処理できます。例えば、ローカルキャッシュからリソースコンテンツを読み取ることで、アプリケーションのパフォーマンスとユーザーエクスペリエンスを向上させることができます。

ここでも IResourceHandler インターフェースを直接実装するのではなく、CefResourceHandler クラスを定義し、そのインターフェースのデフォルト実装クラスである ResourceHandler を継承します。

CefResourceHandler のコンストラクターでは、クロスドメイン問題のみを処理します。その他の要件については、上記のインターフェースのメソッドを参照して資料を検索し、処理してください。

using CefSharp;
using System.IO;

namespace WpfWithCefSharpCacheDemo.Caches;

internal class CefResourceHandler : ResourceHandler
{
    public CefResourceHandler(string filePath, string mimeType = null, bool autoDisposeStream = false,
        string charset = null) : base()
    {
        if (string.IsNullOrWhiteSpace(mimeType))
        {
            var fileExtension = Path.GetExtension(filePath);
            mimeType = Cef.GetMimeType(fileExtension);
            mimeType = mimeType ?? DefaultMimeType;
        }

        var stream = File.OpenRead(filePath);
        StatusCode = 200;
        StatusText = "OK";
        MimeType = mimeType;
        Stream = stream;
        AutoDisposeStream = autoDisposeStream;
        Charset = charset;

        Headers.Add("Access-Control-Allow-Origin", "*");
    }
}

2.1.5. CefResponseFilter

CefSharpでは、IResponseFilter インターフェースはレスポンスコンテンツをフィルタリングするためのもので、ブラウザが受信したレスポンスコンテンツをインターセプトし、変更またはフィルタリングすることで、レスポンスコンテンツの制御と最適化を実現します。

具体的には、IResponseFilter インターフェースには、InitFilterFilterGetSize などのメソッドが定義されています。これらのメソッドは、フィルターの初期化、レスポンスコンテンツのフィルタリング、フィルタリング後のレスポンスコンテンツサイズの取得などに使用できます。例えば:

  1. InitFilter:ブラウザがレスポンスコンテンツを受信したときに呼び出され、フィルターの初期化(フィルターの状態設定、レスポンスヘッダー情報の取得など)に使用できます。

  2. Filter:ブラウザがレスポンスコンテンツを受信したときに呼び出され、レスポンスコンテンツのフィルタリング(レスポンスコンテンツの変更、削除など)に使用できます。

  3. GetSize:ブラウザがレスポンスコンテンツを受信したときに呼び出され、フィルタリング後のレスポンスコンテンツサイズの取得(レスポンスコンテンツの圧縮率の計算など)に使用できます。

私が使用している CefSharp.Wpf のバージョン 89.0.170.0 では、IResponseFilter インターフェースに GetSize メソッドはありません。このバージョンでは、IResponseFilter インターフェースは InitFilterFilter の2つのメソッドのみを定義しています。

このバージョンでフィルタリング後のレスポンスコンテンツサイズを取得する必要がある場合は、Filter メソッド内で自分で計算することを検討してください。例えば、Filter メソッド内でフィルタリング後のレスポンスコンテンツをバッファに書き込み、バッファのサイズを記録し、最後にフィルタリング後のレスポンスコンテンツとバッファサイズを返すことができます。

public class MyResponseFilter : IResponseFilter
{
    private MemoryStream outputStream = new MemoryStream();

    public void Dispose()
    {
        outputStream.Dispose();
    }

    public bool InitFilter()
    {
        return true;
    }

    public FilterStatus Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
    {
        dataInRead = 0;
        dataOutWritten = 0;

        byte[] buffer = new byte[4096];
        int bytesRead = 0;

        do
        {
            bytesRead = dataIn.Read(buffer, 0, buffer.Length);
            if (bytesRead > 0)
            {
                outputStream.Write(buffer, 0, bytesRead);
            }
        } while (bytesRead > 0);

        byte[] outputBytes = outputStream.ToArray();
        dataOut.Write(outputBytes, 0, outputBytes.Length);

        dataInRead = outputBytes.Length;
        dataOutWritten = outputBytes.Length;

        return FilterStatus.Done;
    }

    public int GetResponseFilterBufferSize()
    {
        return 0;
    }

    public int GetResponseFilterDelay()
    {
        return 0;
    }
}

上記のサンプルコードでは、Filter メソッド内でフィルタリング後のレスポンスコンテンツを MemoryStream オブジェクトに書き込み、バッファサイズを記録しています。最後に、Filter メソッドの戻り値としてフィルタリング後のレスポンスコンテンツとバッファサイズを返しています。

まとめると、IResponseFilter インターフェースを実装することで、レスポンスコンテンツをカスタム処理(圧縮、暗号化など)でき、アプリケーションのパフォーマンスとセキュリティを向上させることができます。

本記事のサンプルでは、クラス CefResponseFilter を定義して直接インターフェースを実装し、ファイルキャッシュの実際の操作クラス(リソースダウンロードの実装)とします。

using CefSharp;
using System.IO;

namespace WpfWithCefSharpCacheDemo.Caches;

internal class CefResponseFilter : IResponseFilter
{
    public string LocalCacheFilePath { get; set; }
    private const int BUFFER_LENGTH = 1024;
    private bool isFailCacheFile;


    public FilterStatus Filter(Stream? dataIn, out long dataInRead, Stream? dataOut, out long dataOutWritten)
    {
        dataInRead = 0;
        dataOutWritten = 0;

        if (dataIn == null)
        {
            return FilterStatus.NeedMoreData;
        }

        var length = dataIn.Length;
        var data = new byte[BUFFER_LENGTH];
        var count = dataIn.Read(data, 0, BUFFER_LENGTH);

        dataInRead = count;
        dataOutWritten = count;

        dataOut?.Write(data, 0, count);

        try
        {
            CacheFile(data, count);
        }
        catch
        {
            // ignored
        }

        return length == dataIn.Position ? FilterStatus.Done : FilterStatus.NeedMoreData;
    }

    public bool InitFilter()
    {
        try
        {
            var dirPath = Path.GetDirectoryName(LocalCacheFilePath);
            if (!string.IsNullOrWhiteSpace(dirPath) && !Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
        }
        catch
        {
            // ignored
        }

        return true;
    }

    public void Dispose()
    {
    }

    private void CacheFile(byte[] data, int count)
    {
        if (isFailCacheFile)
        {
            return;
        }

        try
        {
            if (!File.Exists(LocalCacheFilePath))
            {
                using var fs = File.Create(LocalCacheFilePath);
                fs.Write(data, 0, count);
            }
            else
            {
                using var fs = File.Open(LocalCacheFilePath, FileMode.Append);
                fs.Write(data,0,count);
            }
        }
        catch
        {
            isFailCacheFile = true;
            File.Delete(LocalCacheFilePath);
        }
    }
}

2.1.6. CacheFileHelper

キャッシュファイルヘルパークラスです。ページのajaxインターフェースキャッシュホワイトリストやキャッシュファイルパスのルールなどを管理します。

using CefSharp;
using System;
using System.Collections.Generic;
using System.IO;

namespace WpfWithCefSharpCacheDemo.Caches;

internal static class CacheFileHelper
{
    private const string DEV_TOOLS_SCHEME = "devtools";
    private const string DEFAULT_INDEX_FILE = "index.html";

    private static HashSet<string> needInterceptedAjaxInterfaces = new();

    private static string CachePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "caches");

    public static void AddInterceptedAjaxInterfaces(string url)
    {
        if (needInterceptedAjaxInterfaces.Contains(url))
        {
            return;
        }

        needInterceptedAjaxInterfaces.Add(url);
    }

    private static bool IsNeedInterceptedAjaxInterface(string url, ResourceType resourceType)
    {
        var uri = new Uri(url);
        if (DEV_TOOLS_SCHEME == url)
        {
            return false;
        }

        if (ResourceType.Xhr == resourceType && !needInterceptedAjaxInterfaces.Contains(url))
        {
            return false;
        }

        return true;
    }

    public static string? CalculateResourceFileName(string url, ResourceType resourceType)
    {
        if (!IsNeedInterceptedAjaxInterface(url, resourceType))
        {
            return default;
        }

        var uri = new Uri(url);
        var urlPath = uri.LocalPath;

        if (urlPath.StartsWith("/"))
        {
            urlPath = urlPath.Substring(1);
        }

        var subFilePath = urlPath;
        if (ResourceType.MainFrame == resourceType || string.IsNullOrWhiteSpace(urlPath))
        {
            subFilePath = Path.Combine(urlPath, DEFAULT_INDEX_FILE);
        }

        var hostCachePath = Path.Combine(CachePath, uri.Host);
        var fullFilePath = Path.Combine(hostCachePath, subFilePath);
        return fullFilePath;
    }
}

カスタムキャッシュのサブディレクトリは、リソースのドメイン(Host)をディレクトリ名として作成されます。

キャッシュされた dotnet9.com ディレクトリを開くと、ディレクトリ構造がプログラムの公開ディレクトリとほぼ同じであることがわかります。これにより、人間にとってより見やすくなっていますね。

2.2. 発生する可能性のある問題

まず、私が現在直面している問題を1つ挙げ、残りの4点は Token AI が説明を提供しています。

2.2.1. キャッシュされたリソースURLにQueryStringがある場合のサポートが不十分

Route方式(https://dotnet9.com/albums/wpf のようなルーティング)を使用することをお勧めします。QueryString方式(https://dotnet9.com/albums?slug=wpf のようなクエリパラメータ)のキャッシュ方式については、また後で調査します。

どうしてもリソースにQueryStringが必要な場合は、そのようなリソースに対してはキャッシュを開放し、ネットワークリクエストで処理してください。

2.2.2. キャッシュの一貫性の問題

カスタムキャッシュがキャッシュの一貫性を適切に処理しない場合、ブラウザが古い内容や不整合な内容を表示する可能性があります。例えば、ウェブページがキャッシュされていて、そのページがサーバー上で更新された場合、カスタムキャッシュがキャッシュの一貫性を適切に処理していないと、ブラウザが古いページ内容を表示する可能性があります。

2.2.3. キャッシュ容量の問題

カスタムキャッシュがキャッシュ容量を適切に管理しない場合、ブラウザが過剰なメモリやディスク容量を消費する可能性があります。例えば、大量のデータをキャッシュしても、期限切れデータを適時にクリアしたりキャッシュサイズを制限したりしない場合、ブラウザが過剰なメモリやディスク容量を占有する可能性があります。

2.2.4. キャッシュパフォーマンスの問題

カスタムキャッシュがキャッシュのパフォーマンスを適切に処理しない場合、ブラウザのパフォーマンスが低下する可能性があります。例えば、キャッシュの読み書きを適切に処理しない場合、ブラウザの応答速度が遅くなる可能性があります。

2.2.5. キャッシュのセキュリティ問題

カスタムキャッシュがキャッシュのセキュリティを適切に処理しない場合、ブラウザのセキュリティが脅かされる可能性があります。例えば、機密データをキャッシュしても、キャッシュの暗号化と復号を適切に処理しない場合、機密データが漏洩する可能性があります。

そのため、カスタムキャッシュを行う際には、キャッシュの一貫性、キャッシュ容量、キャッシュパフォーマンス、キャッシュセキュリティなどの問題に注意し、ブラウザの正常な動作とセキュリティを確保する必要があります。

参考:

  • CefSharp

  • WeChat技術交流グループ:WeChat(codewf)を追加し、備考に「入群」と記入してください。

  • QQ技術交流グループ:771992300。

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2026/04/22

各OSバージョンの.NETサポート状況(250707更新)

仮想マシンとテストマシンを使用して、各OSバージョンの.NETサポート状況を確認します。OSインストール後、対応するランタイムをインストールし、Stardustエージェントを実行できることを確認します(合格条件)。

続きを読む