ASP.NET Core - 配置系統之配置提供程式

来源:https://www.cnblogs.com/wewant/archive/2023/03/10/17110754.html
-Advertisement-
Play Games

3. 配置提供程式 上面提到,通過 IConfigurationBuilder 的實現類對象,我們可以自由地往配置系統中添加不同的配置提供程式,從而獲取不同來源的配置信息。.NET Core 中,微軟提供了以下這些內置的配置提供程式: 文件配置提供程式 環境變數配置提供程式 命令行配置提供程式 Az ...


3. 配置提供程式

上面提到,通過 IConfigurationBuilder 的實現類對象,我們可以自由地往配置系統中添加不同的配置提供程式,從而獲取不同來源的配置信息。.NET Core 中,微軟提供了以下這些內置的配置提供程式:

  • 文件配置提供程式
  • 環境變數配置提供程式
  • 命令行配置提供程式
  • Azure應用配置提供程式
  • Azure Key Vault 配置提供程式
  • Key-per-file配置提供程式
  • 記憶體配置提供程式
  • 應用機密(機密管理器)
  • 自定義配置提供程式

這裡稍微介紹一下常用的幾個。

3.1 文件配置提供程式

顧名思義,這個就是我們熟悉的配置載入方式,從配置文件中載入配置信息。配置文件多種多樣,.NET Core框架內置支持Json、xml、ini三種格式的文件提供程式:

  • JSON配置提供程式(JsonConfigurationProvider)
  • XML配置提供程式(XmlConfigurationProvider)
  • INI配置提供程式(IniConfigurationProvider)

以上這些配置提供程式,均繼承於抽象基類 FileConfigurationProvider,當一個提供程式中發現重覆的鍵時,提供程式會引發 FormatException,所有類型的文件提供程式都是這樣的機制。

另外,所有文件配置提供程式都支持提供兩個配置參數:

  • optional:bool類型,指示該文件是否是可選的。如果該參數為false,但是指定的文件又不存在,則會報錯。
  • reloadOnChange:bool類型,指示該文件發生更改時,是否要重新載入配置。

3.1.1 JSON配置提供程式

JSON配置提供程式被封裝在 Microsoft.Extensions.Configuration.Json Nuget包中,若通過 ConfigurationBuilder 自行構建配置系統需要先安裝該依賴包。它通過 JsonConfigurationProvider 在運行時從 Json 文件中載入配置。

使用方式非常簡單,通過 IConfigurationBuilder 的實現類對象調用 AddJsonFile 擴展方法指定Json配置文件的路徑即可。以下代碼可用於控制台程式中創建主機並設置配置系統:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var env = context.HostingEnvironment;
        // 添加 json 配置文件
        config.AddJsonFile("appsettings.json",true, true)
            .AddJsonFile($"appsetting.{env.EnvironmentName}.json", true, true);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");

host.Run();

appsetting.json 配置文件中的內容如下:

{
  "Settings": {
    "Provider": "JsonProvider",
    "version": {
      "subKey1": "value",
      "subKey2": 1
    },
    "items": [ "item1", "item2", "item3" ]
  }
}

控制台程式運行之後輸出如下:

image

這樣有一點要註意的是,對於我們手動添加的配置文件需要設置一下文件屬性,讓其在項目生成的時候能夠正常生成到運行目錄,確保應用可以正常獲取到該文件:

image

3.1.2 XML配置提供程式

XML配置提供程式被封裝在 Microsoft.Extensions.Configuration.Xml Nuget包中,通過 XmlConfigurationProvider 類在運行時從 XML 文件載入配置。

使用方式也很簡單,與 JSON 配置提供程式類似,通過 AddXmlFile 擴展方法指定配置文件路徑。

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var env = context.HostingEnvironment;
        //// 添加 json 配置文件
        //config.AddJsonFile("appsettings.json",true, true)
        //    .AddJsonFile($"appsetting.{env.EnvironmentName}.json", true, true);

        config.AddXmlFile("appsettings.xml", true, true);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

xml配置文件內容如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<Settings>
		<Provider>XmlProvider</Provider>
		<version>
			<subKey1>value</subKey1>
			<subKey2>1</subKey2>
		</version>
		<items>item1</items>
		<items>item2</items>
		<items>item3</items>
	</Settings>
</configuration>

運行程式控制台輸出如下:

image

這裡有一個和版本有關的點,對Xml文件中使用同一元素名稱的重覆元素,一般也就是數組,.NET 6及之後的xml配置提供程式會自動為其編製索引,不再需要顯式指定name屬性。如果是 .NET 6 以下的版本則需要這樣了:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<Settings>
		<Provider>XmlProvider</Provider>
		<version>
			<subKey1>value</subKey1>
			<subKey2>1</subKey2>
		</version>
		<items name="itemkey1">item1</items>
		<items name="itemkey2">item2</items>
		<items name="itemkey3">item3</items>
	</Settings>
</configuration>
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:itemkey2")}");

另外xml文件中的屬性也可用於提供值:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <key attribute="value" />
  <section>
    <key attribute="value" />
  </section>
</configuration>

獲取屬性的值可用以下配置鍵:

key:attribute
section:key:attribute

3.1.3 INI配置提供程式

INI 配置提供程式被封裝在 Microsoft.Extensions.Configuration.Ini Nuget包,通過 IniConfigurationProvider 類在運行時從 INI 文件載入配置。使用方式如下:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var env = context.HostingEnvironment;
        //// 添加 json 配置文件
        //config.AddJsonFile("appsettings.json",true, true)
        //    .AddJsonFile($"appsetting.{env.EnvironmentName}.json", true, true);

        //config.AddXmlFile("appsettings.xml", true, true);

        config.AddIniFile("appsettings.ini", true, true);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

ini配置文件內容如下:

[Settings]
Provider="IniProvider"
version:subKey1="value"
version:subKey2=1
items:0="item1"
items:1="item2"
items:3="item3"

運行應用,控制台輸出如下:
image

3.2 環境變數配置提供程式

環境變數配置提供程式被封裝在 Microsoft.Extensions.Configuration.EnvironmentVariables, 通過 EnvironmentVariablesConfigurationProvider 在運行時從環境變數中以鍵值對的方式載入配置。

環境變數一般情況下是配置在機器上的,而不同的操作系統對環境變數的設置要求有所不同,當環境變數存在多層的時候,層級之間的分隔有些支持通過 : 號進行分隔,有些不支持,雙下劃線()是全平臺支持的,所以設置環境變數的時候要使用雙下劃線()來代替冒號(:)。

各種不同的平臺下怎麼去添加環境變數這裡就不細說了,Windows 下大家最起碼都應該知道可以通過 我的電腦 -> 屬性 -> 高級系統設置 去可視化的添加,命令行的方式可閱讀下官方文章: ASP.NET Core 中的配置 | Microsoft Learn,Linux 平臺下可以通過 export 命令臨時添加,或者修改相應的配置文件 ~/.bashrc 或 /etc/profile,大家仔細查一下資料就行了。

處理在機器上直接設置環境變數外,我們開發測試的過程中也可以通過 ASP.NET Core框架下的 launchSettings.json 配置文件設置用於調試的臨時環境變數。在應用啟動調試時,該文件中的環境變數會替代系統的中的環境變數。

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "ConfigurationSample": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5004",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "Custom_settings__Provider": "EnvironmentVariablesProvider",
        "Custom_settings__version__subKey1": "value",
        "Custom_settings__items__0": "item1",
        "Custom_settings__items__1": "item2",
        "Custom_settings__items__2": "item3"
      }
    }
  }
}

環境變數配置提供程式使用也很簡單,註意以下示例為了使用 launchSettings.json 中的環境變數是在 ASP.NET Core項目中測試的。

var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureAppConfiguration(builder =>
{
    builder.Sources.Clear();
    // 篩選前置為 Custom_ 的環境變數,將其載入為應用配置,其他的不載入
    builder.AddEnvironmentVariables("Custom_");
});

var app = builder.Build();

Console.WriteLine($"Settings:Provider: {app.Configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {app.Configuration.GetValue<string>("Settings:items:1")}");

app.Run();

在添加環境變數時,通過指定參數 prefix,只讀取限定首碼的環境變數。不過在讀取環境變數時,會將首碼刪除。如果不指定參數 prefix,那麼會讀取所有環境變數。

當創建預設通用主機(Host)時,預設就已經添加了首碼為 DOTNET_ 的環境變數,如果是在 ASP.NET Core 中,配置了 Web主機時,預設添加了首碼為 ASPNETCORE_ 的環境變數,而後主機載入應用配置時,再根據策略添加了其他的環境變數,如果沒有傳遞 prefix 參數則是所有環境變數。這一塊的載入機制,下麵再細講。

運行應用,控制台輸出如下:
image

除此之外,環境變數提供程式還有一些隱藏的功能點,當沒有向 AddEnvironmentVariables 傳入首碼時,預設也會針對含有以下首碼的環境變數進行特殊處理:

image

這個功能點比較少用到,但是大家看到這個大概都會有點疑惑,具體的形式是怎麼樣的,下麵稍微測試一下

首先在 launchSettings.json 文件中添加多一個環境變數:

"MYSQLCONNSTR_Default": "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;"

之後在應用中列印如下兩個配置:

Console.WriteLine($"ConnectionStrings:Default: { app.Configuration.GetValue<string>("ConnectionStrings:Default") }");
Console.WriteLine($"ConnectionStrings:Default_Provider: { app.Configuration.GetValue<string>("ConnectionStrings:Default_ProviderName") }");

輸出結果如下:
image

也就是說,這種形式的環境變數會被自動轉換為兩個。

3.3 命令行配置提供程式

命令行配置提供程式被封裝在 Microsoft.Extensions.Configuration.CommandLine 包中,通過CommandLineConfigurationProvider在運行時從命令行參數鍵值對中載入配置。

當我們通過 dotnet 命令啟動一個 .NET Core 應用時,我們可以在命令後面追加一些參數,這些參數將在入口文件中被 args 變數接收到。命令行配置提供程式使用如下:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();
        config.AddCommandLine(args);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

之後通過命令行程式啟動應用,並傳入相應的參數:

dotnet ConfigurationSampleConsole.dll Settings:Provider=CommandLineProvider Settings:items:1=item1

image

命令行參數的設置有三種方式:

(1) 使用 = 號連接鍵值:

dotnet ConfigurationSampleConsole.dll Settings:Provider=CommandLineProvider Settings:items:0=item1 Settings:items:1=item2

(2) 使用 / 號表示鍵,值跟在鍵後面,鍵值以空格分隔

dotnet ConfigurationSampleConsole.dll /Settings:Provider CommandLineProvider /Settings:items:0 item1 /Settings:items:1 item2

(3) 使用 -- 符號表示鍵,值跟在鍵後面,鍵值以空格分隔

dotnet ConfigurationSampleConsole.dll --Settings:Provider CommandLineProvider --Settings:items:0 item1 --Settings:items:1 item2

如果值之中本來就有空格的,可以使用 "" 號包括。

dotnet ConfigurationSampleConsole.dll --Settings:Provider CommandLineProvider --Settings:items:0 item1 --Settings:items:1 "test item2"

AddCommandLine 擴展方法提供了重載,允許額外傳入一個參數,該參數提供一個交換映射字典,針對命令行配置參數進行key映射。例如命令行傳入鍵是 name01 ,映射後的的鍵為 project:name。這裡有一些要註意的點:

  • 交換映射key必須以-或--開頭。當使用-開頭時,命令行參數書寫時也要以-開頭,當使用--開頭時,命令行參數書寫時可以以--或/開頭。
  • 交換映射字典中的key不區分大小寫,不能包含重覆 key。如不能同時出現-n和-N,但可以同時出現 -n 和 --n 。
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        var switchMappings = new Dictionary<string, string>
        {
            ["--b1"] = "Settings:Provider",
            ["-b2"] = "Settings:items"
        };

        config.AddCommandLine(args, switchMappings);
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();

image

3.4 記憶體配置提供程式

記憶體配置提供程式就比較簡單了,它直接被包含在 Microsoft.Extensions.Configuration,通過MemoryConfigurationProvider在運行時從記憶體中的集合中載入配置。使用方式如下:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using var host = Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((context, config) =>
    {
        // 清除原有的配置提供程式
        config.Sources.Clear();

        config.AddInMemoryCollection(new Dictionary<string, string> {
            { "Settings:Provider", "InMemoryProvider" },
            { "Settings:items:1", "MemoryItem" }
        });
    })
    .Build();

var configuration = host.Services.GetService<IConfiguration>();

Console.WriteLine($"Settings:Provider: {configuration.GetValue<string>("Settings:Provider")}");
Console.WriteLine($"Settings:items[1]: {configuration.GetValue<string>("Settings:items:1")}");

host.Run();![image]

image

3.5 配置載入順序

上面介紹了一些常用的配置提供程式,這些配置提供程式都是通過擴展方法添加到 ConfigurationBuilder 對象中的,而從上面 ConfigurationBuilder 的源碼可以看出,添加一個配置提供程式的時候其實應該是添加了一個對應的 IConfigurationSource 對象,而後在 ConfigurationBuilder 中被保存到集合中。

這就可以看出,配置系統是允許同時添加多種配置提供程式,支持多來源的配置信息同時存在的。那麼當多個配置處理程式都被添加到配置系統之中,那我們從配置系統中通過配置鍵獲取配置值的時候是怎麼進行的呢,當多個配置提供程式存在相同的配置鍵時,我們獲取到的配置值是哪個呢?

從 ConfigurationRoot 的源碼中可以可以看到,當我們用索引器 API 讀取配置值時,是調用了 GetConfiguration 方法

image

而 GetConfiguration 方法中的邏輯也很簡單,只是遍歷提供程式集合嘗試從提供程式去獲取值,需要關註的是遍歷的順序。

image

這裡的邏輯是這樣子的,倒敘進行遍歷,後添加的配置處理程式先被遍歷,一旦通過key從提供程式中獲取到值就返回結果,不再繼續遍歷。所以添加配置提供程式的順序決定相同配置鍵最終的值, 當多個配置處理程式存在相同鍵時,越後添加的配置提供程式優先順序越高,從最後的一個提供程式獲取到值之後就不再從其他處理程式獲取。

3.6 預設配置來源

上面也有提到通過主機運行和管理應用,在通過主機運行的項目中,主機在啟動的時候就已經預設添加了一些配置提供程式,所以我們創建了一個 ASP.NET Core 模板項目之後就可以獲取到 appsettings.json 等配置文件中的配置信息。下麵介紹一下預設添加的配置提供程式。

Host.CreateDefaultBuilder(String[]) 方法或者 WebApplication.CreateBuilder(args) 方法執行的時候,會按照以下順序添加應用的配置提供程式:

(1) 記憶體配置提供程式
(2) Chained 配置提供程式(添加現有的主機配置)
(3) JSON 配置提供程式 (添加 appsettings.json 配置文件)
(4) JSON 配置提供程式 (添加 appsettings.{Environment}.json 配置文件)
(5) 機密管理器(僅Windows)
(6) 環境變數配置提供程式 (未限定首碼)
(7) 命令行配置提供程式

配置分主機配置和應用配置,主機啟動時應用仍未啟動,主機啟動過程中的配置就是主機配置。上面第一個Chained 配置提供程式就是承接過來的主機配置。而主機配置是按照以下順序載入的:

(1) 環境變數配置提供程式(以 DOTNET_ 為首碼的環境變數)
(2) 命令行配置提供程式 (命令行參數)
(3) 環境變數配置提供程式(以 ASPNETCORE_ 為首碼的環境變數,如果是Web主機的話)

所以最終的應用配置載入順序應該是下麵這樣:

(1) 記憶體配置提供程式
(2) 環境變數配置提供程式(以 DOTNET_ 為首碼的環境變數)
(3) 命令行配置提供程式 (命令行參數)
(4) 環境變數配置提供程式(以 ASPNETCORE_ 為首碼的環境變數,如果是Web主機的話)
(5) JSON 配置提供程式 (添加 appsettings.json 配置文件)
(6) JSON 配置提供程式 (添加 appsettings.{Environment}.json 配置文件)
(7) 機密管理器(僅Windows)
(8) 環境變數配置提供程式 (未限定首碼)
(9) 命令行配置提供程式 (命令行參數)

按照越後面添加的提供程式優先的方式,最終應用配置會覆蓋主機配置,並且最優先是最後添加的命令行配置提供程式,我們可以通過以下方式列印配置系統中所有的配置提供程式,進行驗證:

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

var configurationRoot = (IConfigurationRoot)app.Configuration;
foreach (var provider in configurationRoot.Providers.AsEnumerable())
{
    Console.WriteLine(provider.ToString());
}

app.Run();

最終控制台列印出來的結果如下:

最終控制台列印出來的結果如下:image

雖然應用配置優先,會覆蓋前面的主機配置,但是有一些變數會在初始化主機生成器的時候就提前進行鎖定,並且之後不會受應用配置的影響:

這裡提到環境名稱,其實也就是軟體運行的環境,最最基本的也會分為開發環境、生產環境兩種。軟體運行環境通過環境變數來設置,普通的.NET Core 應用環境變數key為NETCORE_ENVIRONMENT,Web應用環境變數key為ASPNETCORE_ENVIRONMENT,Web應用下如果兩者同時存在,後者會覆蓋前者。軟體應用根據不同的環境會有不同的行為邏輯,例如上面講到的 appsettings.{environment}.json 根據環境而不同的配置文件,例如之前的 入口文件 文章中講到的 Startup 文件根據不同環境的分離配置方式,而我們在代碼中有時也會根據環境處理不同的邏輯,這時候我們可以註入 IHostEnvironment 服務,通過它獲取當前應用的運行環境,入口文件中無論是 WebApplicationBuilder 對象還是 WebApplication 對象都包含該類型的屬性。

通過環境變數設置當前運行環境,其實環境變數的值只是一個字元串,我們可以設置成任意值,這是運行的,.NET Core 框架下 IHostEnvironment 也能夠正常載入到相應的環境名稱,但是.NET Core 預設只提供了對 Development、Production 和 Staging 三種環境的判別,以及相應的處理邏輯和擴展方法,如果是其他的自定義環境則需要開發人員自行進行相應的處理了。和 .NET Core 應用環境相關的知識點大家可以看一下官方文檔: 在 ASP.NET Core 中使用多個環境 | Microsoft Learn

除了上面講到的主機配置,其他還有一些主機配置,例如URLS,但這個是可以通過應用配置設置的,讀取相應的配置值時也應用從應用配置讀取。

URLS 配置Web應用啟動後的訪問地址,這個配置可以多個地方設置,其中命令行參數最優先,其他地方設置的應該被命令行參數覆蓋。但是如果通過Kestrel 終結點方式設置了Web應用的訪問地址,那Kestrel 終結點的配置將覆蓋其他所有的訪問地址的配置。

如在 appsettings.json 中添加以下配置:

"Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://localhost:9999"
      }
    }
  }

那麼以下幾種方式設置的 URLS 都會失效:

  • UseUrls
  • 命令行上的 --urls
  • 環境變數 ASPNETCORE__URLS

也就是說,就算我們用以下命令啟動應用,應用最終的訪問地址還是以Kestrel終結點配置的為準:

dotnet run --urls="https://localhost:7777"

Kestrel 配置與 URLS 配置不是一個參數,我們可以通過在命令行或者環境變數中設置 kestrel 中間點配置來覆蓋 appsettings.json 中的,這又回到配置提供程式的優先順序問題了。

set Kestrel__Endpoints__Https__Url=https://localhost:8888

dotnet run Kestrel__Endpoints__Https__Url=https://localhost:8888

在主機啟動的邏輯中Kestrel具備更高的最終優先順序,但是其實主機內部是先根據URLS創建了一個終結點,之後又替換為 Kestrel 配置的終結點的。通過應用啟動時的控制台輸出可以看出。

image

這種情況對於單機應用沒有什麼影響,但是對於使用自動服務發現的微服務架構而言就可能有問題了,可能導致註冊服務註冊中心的終結點是第一個,而後應用終結點又被改變,導致註冊中心記錄的服務終結點和實際的不一致。

這一篇的內容比較多,但是不大好拆分,整個知識點是一個整體,通過這一章的內容相信大家能夠對 .NET Core 框架配置系統內部的工作原理有一個詳細的瞭解。



參考文章:

ASP.NET Core 中的配置 | Microsoft Learn
配置 - .NET | Microsoft Learn
理解ASP.NET Core - 配置(Configuration)



ASP.NET Core 系列:
目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core - 配置系統之配置添加


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 2023Java面試題最經典的問題之一了,非常經典的Java基礎知識,一定要學會! 在Java中,String類被設計成final,這意味著它的值在創建後不可更改。這是因為字元串在Java中使用廣泛,作為文本處理、網路通信等方面的核心數據類型。如果String類是可變的,那麼在使用時可能會出現安全問 ...
  • 最近發現一個不錯的免費開源學習項目:30天學會Python 如果您最近有學習Python的打算,不妨看看這個是否適合你? 項目地址:https://github.com/Asabeneh/30-Days-Of-Python 博客地址:https://blog.didispace.com/tj-30- ...
  • 最新版 IDEA 2022.3.2 中配置熱載入工具 DevTools 在SpringBoot開發調試中,如果我每行代碼的修改都需要重啟再調試,可能比較費時間;SpringBoot團隊針對此問題提供了spring-boot-devtools(簡稱devtools)插件,用此插件提升開發調試的效率。 ...
  • 前言 之前寫過一篇基於ML.NET的手部關鍵點分類的博客,可以根據圖片進行手部的提取分類,於是我就將手勢分類和攝像頭數據結合,集成到了我開發的電子腦殼軟體里。 電子腦殼是一個為稚暉君開源的桌面機器人ElectronBot提供一些軟體功能的桌面程式項目。它是由綠蔭阿廣也就是我開發的,使用了微軟的WAS ...
  • 最近在使用 Blazor 開發管理後臺時遇到瞭如下的問題,我這裡後臺整體採用了 AntDesignBlazor 組件庫,在上線之後發現ReuseTabs組件在使用過程中,如果預設 / 沒有指定為項目的base href,打開標簽頁後,相互切換會導致url錯誤。 本地開發的時候項目是直接啟動運行的,所 ...
  • 在DNF中,角色貼圖以.ani文件的坐標為中心,NPK中png的坐標為繪製坐標(坐上)進行繪製,繪製的結果如圖所示: 原點坐標-232,-333 原點坐標-232,-333 皮膚坐標207,224 皮膚坐標207,224 太刀柄194,264 太刀柄194,264 太刀刃213,283 太刀刃213 ...
  • 概述 非同步這個概念在不同語境下有不同的解釋,比如在一個單核CPU里開啟兩個線程執行兩個函數,通常認為這種調用是非同步的,但對於CPU來說它是單核不可能同時運行兩個函數,不過是由系統調度在不同的時間分片中執行。一般來說,如果兩個工作能同時進行,就認為是非同步的。在編程中,它通常代表函數的調用可以在不執行完 ...
  • 1 - 文本控制項 我們熟悉的文本控制項不外乎TextBox,RichTextBox。在WPF中還有一個PasswordBox,不過區分於前者的區別就是PasswordBox是直接繼承於Control的比較特殊,前三者是繼承於TextBoxBase的。接下來我們就簡單介紹下這幾個控制項。 1.1 - 多行 ...
一周排行
    -Advertisement-
    Play Games
  • 一個自定義WPF窗體的解決方案,借鑒了呂毅老師的WPF製作高性能的透明背景的異形視窗一文,併在此基礎上增加了滑鼠穿透的功能。可以使得透明窗體的滑鼠事件穿透到下層,在下層窗體中響應。 ...
  • 在C#中使用RabbitMQ做個簡單的發送郵件小項目 前言 好久沒有做項目了,這次做一個發送郵件的小項目。發郵件是一個比較耗時的操作,之前在我的個人博客裡面回覆評論和友鏈申請是會通過發送郵件來通知對方的,不過當時只是簡單的進行了非同步操作。 那麼這次來使用RabbitMQ去統一發送郵件,我的想法是通過 ...
  • 當你使用Edge等瀏覽器或系統軟體播放媒體時,Windows控制中心就會出現相應的媒體信息以及控制播放的功能,如圖。 SMTC (SystemMediaTransportControls) 是一個Windows App SDK (舊為UWP) 中提供的一個API,用於與系統媒體交互。接入SMTC的好 ...
  • 最近在微軟商店,官方上架了新款Win11風格的WPF版UI框架【WPF Gallery Preview 1.0.0.0】,這款應用引入了前沿的Fluent Design UI設計,為用戶帶來全新的視覺體驗。 ...
  • 1.簡單使用實例 1.1 添加log4net.dll的引用。 在NuGet程式包中搜索log4net並添加,此次我所用版本為2.0.17。如下圖: 1.2 添加配置文件 右鍵項目,添加新建項,搜索選擇應用程式配置文件,命名為log4net.config,步驟如下圖: 1.2.1 log4net.co ...
  • 之前也分享過 Swashbuckle.AspNetCore 的使用,不過版本比較老了,本次演示用的示例版本為 .net core 8.0,從安裝使用開始,到根據命名空間分組顯示,十分的有用 ...
  • 在 Visual Studio 中,至少可以創建三種不同類型的類庫: 類庫(.NET Framework) 類庫(.NET 標準) 類庫 (.NET Core) 雖然第一種是我們多年來一直在使用的,但一直感到困惑的一個主要問題是何時使用 .NET Standard 和 .NET Core 類庫類型。 ...
  • WPF的按鈕提供了Template模板,可以通過修改Template模板中的內容對按鈕的樣式進行自定義。結合資源字典,可以將自定義資源在xaml視窗、自定義控制項或者整個App當中調用 ...
  • 實現了一個支持長短按得按鈕組件,單擊可以觸發Click事件,長按可以觸發LongPressed事件,長按鬆開時觸發LongClick事件。還可以和自定義外觀相結合,實現自定義的按鈕外形。 ...
  • 一、WTM是什麼 WalkingTec.Mvvm框架(簡稱WTM)最早開發與2013年,基於Asp.net MVC3 和 最早的Entity Framework, 當初主要是為瞭解決公司內部開發效率低,代碼風格不統一的問題。2017年9月,將代碼移植到了.Net Core上,併進行了深度優化和重構, ...