CefSharp自定義緩存實現

来源:https://www.cnblogs.com/Dotnet9-com/archive/2023/04/26/17357720.html
-Advertisement-
Play Games

大家好,我是沙漠盡頭的狼。 上文介紹了《C#使用CefSharp內嵌網頁-並給出C#與JS的交互示例》,本文介紹CefSharp的緩存實現,先來說說添加緩存的好處: 提高頁面載入加速:CefSharp緩存可以緩存已經載入過的頁面和資源,當用戶再次訪問相同的頁面時,可以直接從緩存中載入,而不需要重新下 ...


大家好,我是沙漠盡頭的狼。

上文介紹了《C#使用CefSharp內嵌網頁-並給出C#與JS的交互示例》,本文介紹CefSharp的緩存實現,先來說說添加緩存的好處:

  1. 提高頁面載入加速:CefSharp緩存可以緩存已經載入過的頁面和資源,當用戶再次訪問相同的頁面時,可以直接從緩存中載入,而不需要重新下載和解析頁面和資源,從而加快頁面載入速度。
  2. 減少網路流量:使用緩存可以減少網路流量,因為已經下載過的資源可以直接從緩存中讀取,而不需要重新下載。
  3. 提高用戶體驗:由於緩存可以提高頁面載入速度,因此可以提高用戶的體驗,用戶可以更快地訪問頁面和資源,從而更加愉快地使用應用程式。
  4. 減少伺服器負載:使用緩存可以減少伺服器的負載,因為已經下載過的資源可以直接從緩存中讀取,而不需要重新生成和發送。
  5. 離線訪問:可以使應用程式支持離線訪問,因為它可以緩存已經下載過的頁面和資源,當用戶沒有網路連接時,可以直接從緩存中載入頁面和資源。

總之,使用緩存可以提高應用程式的性能和用戶體驗,減少網路流量和伺服器負載,並支持離線訪問,是一個非常有用的特性。

本文示例:Github

斷網情況下,演示載入已經緩存的百度百度翻譯Dotnet9首頁Dotnet9關於4個頁面:

接下來講解緩存的實現方式。

1. 預設緩存實現

CefSharp的預設緩存實現方式是基於Chromium的緩存機制。Chromium使用了兩種類型的緩存:記憶體緩存和磁碟緩存。

1.1. 記憶體緩存

記憶體緩存是一個基於LRU(最近最少使用)演算法的緩存,它緩存了最近訪問的頁面和資源。記憶體緩存的大小是有限的,當緩存達到最大大小時,最近最少使用的頁面和資源將被刪除。

記憶體緩存無法通過CefSharp.WPF的API進行設置。具體來說,Chromium會在記憶體中維護一個LRU(Least Recently Used)緩存,用於存儲最近訪問的網頁數據。當緩存空間不足時,Chromium會根據LRU演算法自動清除最近最少使用的緩存數據,以騰出空間存儲新的數據。

在CefSharp.WPF中,我們可以通過調用Cef.GetGlobalRequestContext().ClearCacheAsync()方法來清除記憶體緩存中的數據。該方法會清除所有緩存數據,包括記憶體緩存和磁碟緩存。如果只需要清除記憶體緩存,可以調用Cef.GetGlobalRequestContext().ClearCache(CefCacheType.MemoryCache)方法。

需要註意的是,由於記憶體緩存是由Chromium自身維護的,因此我們無法直接控制其大小。如果需要控制緩存大小,可以通過設置磁碟緩存的大小來間接控制記憶體緩存的大小。

1.2. 磁碟緩存

磁碟緩存是一個基於文件系統的緩存,它緩存了已經下載的頁面和資源。磁碟緩存的大小也是有限的,當緩存達到最大大小時,最早的頁面和資源將被刪除。

CefSharp.WPF的磁碟緩存是通過設置CefSettings中的CachePath屬性來實現的。具體來說,我們可以通過以下代碼設置磁碟緩存的路徑:

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自身控制的,我們可以通過設置CacheController的SetCacheLimit方法來控制緩存數據存儲在磁碟上的最大空間。該方法接受一個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)
    {
        // 一個請求用一個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方法:在這個方法里,我們可以實現給頁面傳遞header參數。
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.Wpf89.0.170.0版本中的IResponseFilter介面沒有GetSize方法。在該版本中,IResponseFilter介面只定義了兩個方法:InitFilterFilter

如果在該版本中您需要獲取過濾後的響應內容大小,可以考慮在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. 可能存在的問題

第一點,站長目前遇到的問題,後面4點由Token AI提供解釋。

2.2.1. 對緩存的資源URL帶QueryString的方式支持不好

建議用Route(路由的方式:https://dotnet9.com/albums/wpf)代替QueryString(查詢參數的試工:https://dotnet9.com/albums?slug=wpf)的方式,站長有空再研究下QueryString的緩存方式。

如果確實資源帶QueryString,那對於這種資源就放開緩存,直接通過網路請求吧。

2.2.2. 緩存一致性問題

如果自定義緩存不正確地處理了緩存一致性,可能會導致瀏覽器顯示過期的內容或者不一致的內容。例如,如果緩存了一個網頁,但是該網頁在伺服器上已經被更新了,如果自定義緩存沒有正確地處理緩存一致性,可能會導致瀏覽器顯示過期的網頁內容。

2.2.3. 緩存空間問題

如果自定義緩存沒有正確地管理緩存空間,可能會導致瀏覽器占用過多的記憶體或者磁碟空間。例如,如果自定義緩存緩存了大量的數據,但是沒有及時清理過期的數據或者限制緩存的大小,可能會導致瀏覽器占用過多的記憶體或者磁碟空間。

2.2.4. 緩存性能問題

如果自定義緩存沒有正確地處理緩存性能,可能會導致瀏覽器的性能下降。例如,如果自定義緩存沒有正確地處理緩存的讀取和寫入,可能會導致瀏覽器的響應速度變慢。

2.2.5. 緩存安全問題

如果自定義緩存沒有正確地處理緩存安全,可能會導致瀏覽器的安全性受到威脅。例如,如果自定義緩存緩存了敏感數據,但是沒有正確地處理緩存的加密和解密,可能會導致敏感數據泄露。

因此,在自定義緩存時,需要註意處理緩存一致性、緩存空間、緩存性能和緩存安全等問題,以確保瀏覽器的正常運行和安全性。

參考:

時間如流水,只能流去不流回。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 教程簡介 Java 8 (又稱為 jdk 1.8) 是 Java 語言開發的一個主要版本。 Java 8 是oracle公司於2014年3月發佈,可以看成是自Java 5 以來最具革命性的版本。Java 8為Java語言、編譯器、類庫、開發工具與JVM帶來了大量新特性。 Java 8入門教程 - 從 ...
  • 教程簡介 XAML是eXtensible Application Markup Language的英文縮寫,相應的中文名稱為可擴展應用程式標記語言,它是微軟公司為構建應用程式用戶界面而創建的一種新的描述性語言。XAML提供了一種便於擴展和定位的語法來定義和程式邏輯分離的用戶界面,而這種實現方式和AS ...
  • 協程 進程和線程 進程 ​ 當運行一個應用程式的時候,操作系統會為這個應用程式啟動一個進程。可以將這個進程看作一個包含了應用程式在運行中需要用到和維護的各種資源的容器。這些資源包括但不限於記憶體地址空間、文件和設備的句柄以及線程 線程 ​ 一個線程是一個執行空間,這個空間會被操作系統調度來運行函數中所 ...
  • 編譯 簡單就是把代碼跑一哈,然後我們的代碼 .java文件 就被編譯成了 .class 文件 反編譯 就是針對編譯生成的 jar/war 包 裡面的 .class 文件 逆向還原回來,可以看到你的代碼寫的啥。 比較常用的反編譯工具 JD-GUI ,直接把編譯好的jar丟進去,大部分都能反編譯看到源碼 ...
  • 1.1堆空間結構 Java 的自動記憶體管理主要是針對對象記憶體的回收和對象記憶體的分配。同時,Java 自動記憶體管理最核心的功能是 堆 記憶體中對象的分配與回收。Java 堆是垃圾收集器管理的主要區域,因此也被稱作 GC 堆。Eden 區、兩個 Survivor 區 S0 和 S1 都屬於新生代,中間一層 ...
  • 靜態域 **如果將域定義為 static,每個類中只有一個這樣的域。而每一個對象對於所有的實例域卻都有自己的一份拷貝。**例如,假定需要給每一個雇員賦予唯一的標識碼。這裡給 Employee 類添加一個實例域 id 和一個靜態域 nextld: class Employee { private st ...
  • #include <stdlib.h> int main() { // 定義要打開的URL char* url = "https://rjku.gitee.io/"; // 調用系統命令以預設瀏覽器打開URL char command[100]; sprintf(command, "open %s" ...
  • 最近組件庫更新比較頻繁,有些同學感覺有點迷茫,就著今天剛上了張老闆一節課立馬擼個新的上手教程回饋社區, ;-> 1.新建工程b18QuickStartv757,將項目添加到解決方案中 dotnet new blazorserver -o b18QuickStartv757 dotnet sln ad ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...