[Abp 源碼分析]十三、多語言(本地化)處理

来源:https://www.cnblogs.com/myzony/archive/2018/08/18/9496490.html
-Advertisement-
Play Games

0.簡介 如果你所開發的需要走向世界的話,那麼肯定需要針對每一個用戶進行不同的本地化處理,有可能你的客戶在日本,需要使用日語作為顯示文本,也有可能你的客戶在美國,需要使用英語作為顯示文本。如果你還是一樣的寫死錯誤信息,或者描述信息,那麼就無法做到多語言適配。 Abp 框架本身提供了一套多語言機制來幫 ...


0.簡介

如果你所開發的需要走向世界的話,那麼肯定需要針對每一個用戶進行不同的本地化處理,有可能你的客戶在日本,需要使用日語作為顯示文本,也有可能你的客戶在美國,需要使用英語作為顯示文本。如果你還是一樣的寫死錯誤信息,或者描述信息,那麼就無法做到多語言適配。

Abp 框架本身提供了一套多語言機制來幫助我們實現本地化,基本思路是 Abp 本身維護一個鍵值對集合。只需要將展示給客戶的文字信息處都使用一個語言 Key 來進行填充,當用戶登錄系統之後,會取得當前用戶的區域文化信息進行文本渲染。

0.1 如何使用

我們首先來看一下如何定義一個多語言資源並使用。首先 Abp 自身支持三種類型的本地化資源來源,第一種是 XML 文件,第二種則是 JSON 文件,第三種則是內嵌資源文件,如果這三種都不能滿足你的需求,你可以自行實現 ILocalizationSource  介面來返回多語言資源。

小提示:

Abp Zero 模塊就提供了資料庫持久化存儲多語言資源的功能。

0.1.1 定義應用程式支持的語言

如果你需要為你的應用程式添加不同語言的支持,就必須在你任意模塊的預載入方法當中添加語言來進行配置:

Configuration.Localization.Languages.Add(new LanguageInfo("en", "English", "famfamfam-flag-england", true));
Configuration.Localization.Languages.Add(new LanguageInfo("tr", "Türkçe", "famfamfam-flag-tr"));

例如以上代碼,就能夠讓我們的程式擁有針對英語與土耳其語的多語言處理能力。

這裡的 famfamfam-flag-englandfamfamfam-flag-tr 是一個 CSS 類型,是 Abp 為前端展示所封裝的小國旗圖標。

0.1.2 建立多語言資源文件

有了語言之後,Abp 還需要你提供標準的多語言資源文件,這裡我們以 自帶的 XML 資源文件為例,其文件名稱為 Abp-zh-Hans.xml ,路徑為 Abp\Localization\Sources\AbpXmlSource

<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="zh-Hans">
  <texts>
    <text name="SmtpHost">SMTP主機</text>
    <text name="SmtpPort">SMTP埠</text>
    <text name="Username">用戶名</text>
    <text name="Password">密碼</text>
    <text name="DomainName">功能變數名稱</text>
    <text name="UseSSL">使用SSL</text>
    <text name="UseDefaultCredentials">使用預設驗證</text>
    <text name="DefaultFromSenderEmailAddress">預設發件人郵箱地址</text>
    <text name="DefaultFromSenderDisplayName">預設發件人名字</text>
    <text name="DefaultLanguage">預設語言</text>
    <text name="ReceiveNotifications">接收通知</text>
    <text name="CurrentUserDidNotLoginToTheApplication">當前用戶沒有登錄到系統!</text>
    <text name="TimeZone">時區</text>
    <text name="AllOfThesePermissionsMustBeGranted">您沒有許可權進行此操作,您需要以下許可權: {0}</text>
    <text name="AtLeastOneOfThesePermissionsMustBeGranted">您沒有許可權進行此操作,您至少需要下列許可權的其中一項: {0}</text>
    <text name="MainMenu">主菜單</text>
  </texts>
</localizationDictionary>

每個文件內部,會有一個 <localizationDictionary culture="zh-Hans"> 節點用於說明當前文件是針對於哪個區域適用的,而在其 <texts> 內部則就是結合鍵值對的形式,name 裡面的內容就是多語言文本項的鍵,在標簽內部的就是其真正的值。

打開一個針對俄語國家的 XML 資源文件,文件名稱叫做 Abp-ru.xml

<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="ru">
  <texts>
    <text name="SmtpHost">SMTP сервер</text>
    <text name="SmtpPort">SMTP порт</text>
    <text name="Username">Имя пользователя</text>
    <text name="Password">Пароль</text>
    <text name="DomainName">Домен</text>
    <text name="UseSSL">Использовать SSL</text>
    <text name="UseDefaultCredentials">Использовать учетные данные по умолчанию</text>
    <text name="DefaultFromSenderEmailAddress">Электронный адрес отправителя по умолчанию</text>
    <text name="DefaultFromSenderDisplayName">Имя отправителя по умолчанию</text>
    <text name="DefaultLanguage">Язык по умолчанию</text>
    <text name="ReceiveNotifications">Получать уведомления</text>
    <text name="CurrentUserDidNotLoginToTheApplication">Текущий пользователь не вошёл в приложение!</text>
  </texts>
</localizationDictionary>

可以看到 Key 值都是一樣的,只是其 <text> 內部的值根據區域國家的不同值不一樣而已。

其次從文件名我們就可以看到需要使用 XML 資源文件對於文件的命名格式會有一定要求,還是以 Abp 自帶的資源文件為例,可以看一下他們基本上都是由 {SourceName}-{CultureInfo}.xml 這樣構成的。

0.1.3 註冊本地化的 XML 資源

那麼如果我們需要註冊之前的兩個 XML 資源到 Abp 框架當中的話,則需要在預載入模塊處通過如下代碼來執行註冊,並且需要右鍵 XML 文件,更改其構建操作為 內嵌資源

Configuration.Localization.Sources.Add(
    new DictionaryBasedLocalizationSource(
        // 本地化資源名稱
        AbpConsts.LocalizationSourceName,
        // 數據源提供者,這裡使用的是 XML ,除了 XML 提供者,還有 JSON 等
        new XmlEmbeddedFileLocalizationDictionaryProvider(
            typeof(AbpKernelModule).GetAssembly(), "Abp.Localization.Sources.AbpXmlSource"
        )));

0.1.4 獲取多語言文本

如果你需要在某處獲取指定 Key 所對應的具體顯示文本,只需要註入 ILocalizationManager ,通過其 GetString() 方法就可以獲得具體的值。如果你需要獲取本地化資源的地方不能夠使用依賴註入,你可以使用 LocalizationHelper 靜態類來進行操作。

var @string = _localizationManager.GetString("Abp", "MainMenu");

它預設是從 Thread.CurrentThread.CurrentUICulture 獲取到的當前區域信息,從而來取得某個 Key 所對應的顯示值,而當前區域信息是由 Abp 註入的一系列 RequestCultureProviders 所提供的,他按照以下順序來進行設置。

  1. QueryStringRequestCultureProvider(ASP .NET Core 預設提供):該預設提供器使用的是 QueryStringculture&ui-culture 所提供的區域文化信息來初始化該值,例如:culture=es-MX&ui-culture=es-MX
  2. AbpUserRequestCultureProvider (Abp 提供):該提供器會讀取當前用戶的 IAbpSession 信息,並且從 ISettingManager 中獲取用戶所配置的 "Abp.Localization.DefaultLanguageName" 屬性,將其作為預設的區域文化信息。
  3. AbpLocalizationHeaderRequestCultureProvider (Abp 提供):使用每次請求頭當中的 .AspNetCore.Culture 值作為當前的區域文化信息,例如 c=en|uic=en-US
  4. CookieRequestCultureProvider (ASP .NET Core 提供):使用每次請求的 Cookie 當中 Key 為 .AspNetCore.Culture 值作為當前區域文化信息。
  5. AbpDefaultRequestCultureProvider (Abp 提供):如果之前這些提供器都沒有為當前區域文化賦值,則從 ISettingMananger 當中取得 Abp.Localization.DefaultLanguageName 的預設值。
  6. AcceptLanguageHeaderRequestCultureProvider (ASP .NET Core 預設提供):該提供器最終會使用用戶每次請求時傳遞的 Accept-Language 頭部作為當前區域文化信息。

小提示:

這裡 Abp 註入的提供器是有順序的,註入這麼多提供器就是為了最後確定當前用戶的區域文化信息以便展示相應的語言文本。

1.啟動流程

1.1 啟動流程圖

1.2 代碼流程

根據使用方法我們可以得知,要配置 Abp 的多語言,必須得等 IAbpStartupConfiguration 初始化完畢才可以。即在 AbpBootstrapperInitialize() 方法之中:

public virtual void Initialize()
{
    // ... 其他代碼
    // 註入 IAbpStartupConfiguration 配置與本地化資源配置
    IocManager.IocContainer.Install(new AbpCoreInstaller());

    // ... 其他代碼
    // 初始化 AbpStartupConfiguration 類型
    IocManager.Resolve<AbpStartupConfiguration>().Initialize();

    // ... 其他代碼
}

配置類裡面包含了用戶所配置的所有語言與多語言資源信息,在被成功註入到 Ioc 容器之後,Abp 就開始使用本地化資源管理器來初始化這些多語言數據了。

public override void PostInitialize()
{
    // 註冊缺少的組件,防止遺漏註冊組件
    RegisterMissingComponents();

    IocManager.Resolve<SettingDefinitionManager>().Initialize();
    IocManager.Resolve<FeatureManager>().Initialize();
    IocManager.Resolve<PermissionManager>().Initialize();
    
    // 重點在這裡,這個 PostInitialize 方法是存放在核心模塊當中的,在這裡調用了本地化資源管理器的初始化方法
    IocManager.Resolve<LocalizationManager>().Initialize();
    IocManager.Resolve<NotificationDefinitionManager>().Initialize();
    IocManager.Resolve<NavigationManager>().Initialize();

    if (Configuration.BackgroundJobs.IsJobExecutionEnabled)
    {
        var workerManager = IocManager.Resolve<IBackgroundWorkerManager>();
        workerManager.Start();
        workerManager.Add(IocManager.Resolve<IBackgroundJobManager>());
    }
}

具體 LocalizationManager 及其內部的實現我們在下一節代碼分析中詳細進行講述。

這些動作僅僅是在註入 Abp 框架的時候所需要執行的一些步驟,如果你要啟用多語言,需要在 ASP .NET Core 程式的 Startup 類中的 Configure() 處通過更改 UseAbpRequestLocalization 狀態為 True,才會將區域文化識別中間件註入到程式當中。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseAbp(options =>
    {
        options.UseAbpRequestLocalization = false; //disable automatic adding of request localization
    });

    //...authentication middleware(s)

    app.UseAbpRequestLocalization(); //manually add request localization

    //...other middlewares

    app.UseMvc(routes =>
    {
        //...
    });
}

其實這裡的 UseAbpRequestLocalization() 就已經將上文說的那些 RequestProvider 按照順序依次註入到 MVC 之中了。

2.代碼分析

Abp 框架針對本地化處理相關的類型與方法定義都存放在 Abp 庫的 Localization 文件夾下。關係還是相對複雜的,這裡我們先從其核心的 Abp 庫針對於多語言的處理開始講起。

2.1 多語言模塊配置

Abp 需要使用的所有信息都是由用戶在自己啟動模塊的 PreInitialize() 當中,通過 ILocalizationConfiguration 進行註入配置。也就是說在 ILocalizationConfiguration 內部,主要是包含了語言,與多語言資源提供者兩種重點信息。

public interface ILocalizationConfiguration
{
    // 當前應用程式可配置的語言列表
    IList<LanguageInfo> Languages { get; }

    // 本地化資源列表
    ILocalizationSourceList Sources { get; }

    // 是否啟用多語言(本地化) 系統
    bool IsEnabled { get; set; }

    // 以下四個布爾類型的參數主要用於確定當沒有找到多語言文本時的處理邏輯,預設都為 True
    bool ReturnGivenTextIfNotFound { get; set; }

    bool WrapGivenTextIfNotFound { get; set; }

    bool HumanizeTextIfNotFound { get; set; }

    bool LogWarnMessageIfNotFound { get; set; }
}

2.2 語言信息

當前應用程式能夠支持哪一些語言,取決於用戶在預載入的時候給多語言模塊配置對象分配了哪些語言。通過第 0.1.1 節我們看到用戶可以直接通過初始化一個新的 LanguageInfo 對象,將其添加到 Languages 屬性之中。

public class LanguageInfo
{
    /// <summary>
    /// 區域文化代碼名稱
    /// 應該是一個有效的區域文化代碼名稱,更多的可以通過 CultureInfo 靜態類獲得所有文化代碼。
    /// 例如: "en-US" 是北美適用的, "tr-TR" 適用於土耳其。
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 該語言預設應該展示的語言名稱。
    /// 例如: 英語應該展示為 "English", "zh-Hans" 應該展示為 "簡體中文"
    /// </summary>
    public string DisplayName { get; set; }

    /// <summary>
    /// 用於展示的圖標 CSS 類名,可選參數
    /// </summary>
    public string Icon { get; set; }

    /// <summary>
    /// 是否為預設語言
    /// </summary>
    public bool IsDefault { get; set; }

    /// <summary>
    /// 該語言是否被禁用
    /// </summary>
    public bool IsDisabled { get; set; }

    /// <summary>
    /// 語言的展示方式是自左向右還是自右向左
    /// </summary>
    public bool IsRightToLeft
    {
        get
        {
            try
            {
                return CultureInfo.GetCultureInfo(Name).TextInfo?.IsRightToLeft ?? false;
            }
            catch
            {
                return false;
            }
        }
    }

    public LanguageInfo(string name, string displayName, string icon = null, bool isDefault = false, bool isDisabled = false)
    {
        Name = name;
        DisplayName = displayName;
        Icon = icon;
        IsDefault = isDefault;
        IsDisabled = isDisabled;
    }
}

關於語言的定義還是相當簡單的,主要參數就是語言的 區域文化代碼展示的名稱,其餘的都可以是可選參數。

小提示:

關於當前系統所支持的區域文化代碼,可以通過執行 CultureInfo.GetCultures(CultureTypes.AllCultures); 得到。

2.3 語言管理器

Abp 針對語言也提供了一個管理器,介面叫做 ILanguageManager,定義簡單,兩個方法。

public interface ILanguageManager
{
    // 獲得當前語言
    LanguageInfo CurrentLanguage { get; }

    // 獲得所有語言
    IReadOnlyList<LanguageInfo> GetLanguages();
}

實現也不複雜,它內部的實現就是從一個 ILanguageProvider 拿取有哪一些語言數據。

private readonly ILanguageProvider _languageProvider;

public IReadOnlyList<LanguageInfo> GetLanguages()
{
    return _languageProvider.GetLanguages();
}

// 獲取當前語言,其實就是獲取的 CultureInfo.CurrentUICulture.Name 的信息,然後去查詢語言集合。
private LanguageInfo GetCurrentLanguage()
{
    var languages = _languageProvider.GetLanguages();
    
    // ... 省略了的代碼
    var currentCultureName = CultureInfo.CurrentUICulture.Name;

    var currentLanguage = languages.FirstOrDefault(l => l.Name == currentCultureName);
    if (currentLanguage != null)
    {
        return currentLanguage;
    }
    
    // ... 省略了的代碼
    
    return languages[0];
}

預設實現就是直接讀取之前通過 Configuration 的 Languages 裡面的數據。

在 Abp.Zero 模塊還有兩外一個實現,叫做 ApplicationLanguageProvider ,這個提供者則是從資料庫表 ApplicationLanguage 獲取的這些語言列表數據,並且這些語言信息還與租戶有關,不同的租戶他所能夠獲得到的語言數據也不一樣。

public IReadOnlyList<LanguageInfo> GetLanguages()
{
    // 可以看到這裡傳入的當前登錄用戶的租戶 Id,通過這個參數去查詢的語言表數據
    var languageInfos = AsyncHelper.RunSync(() => _applicationLanguageManager.GetLanguagesAsync(AbpSession.TenantId))
        .OrderBy(l => l.DisplayName)
        .Select(l => l.ToLanguageInfo())
        .ToList();

    SetDefaultLanguage(languageInfos);

    return languageInfos;
}

2.4 本地化資源

2.4.1 本地化資源列表

在多語言模塊配置內部使用的是 ILocalizationSourceList 類型的一個 Sources 屬性,該類型其實就是繼承自 IList<ILocalizationSource> 的一個具體實現而已,一個類型為 ILocalizationSource 的集合,不過其擴展了一個

Extensions 屬性用於存放擴展的多語言數據欄位。

2.4.2 本地化資源

其介面定義為 ILocalizationSource ,Abp 預設為我們實現了四種本地化資源的實現。

第一個是空實現,可以跳過,第二個則是針對資源文件進行讀取的的本地化資源,第三個是基於字典的的本地化資源定義,最後一個是由 Abp Zero 模塊所提供的資料庫版本的多語言資源定義。

首先看一下該介面的定義:

public interface ILocalizationSource
{
    // 本地化資源唯一的名稱
    string Name { get; }

    // 用於初始化本地化資源,在 Abp 框架初始化的時候被調用
    void Initialize(ILocalizationConfiguration configuration, IIocResolver iocResolver);

    // 從當前本地化資源中獲取給定關鍵字的多語言文本項,為用戶當前語言
    string GetString(string name);

    // 從當前本地化資源中獲取給定關鍵字與區域文化的多語言文本項
    string GetString(string name, CultureInfo culture);

    // 作用同上,只不過不存在會返回 NULL
    string GetStringOrNull(string name, bool tryDefaults = true);

    // 作用同上,只不過不存在會返回 NULL
    string GetStringOrNull(string name, CultureInfo culture, bool tryDefaults = true);

    // 獲得當前語言所有的多語言文本項集合
    IReadOnlyList<LocalizedString> GetAllStrings(bool includeDefaults = true);

    // 獲得給定區域文化的所有多語言文本項集合
    IReadOnlyList<LocalizedString> GetAllStrings(CultureInfo culture, bool includeDefaults = true);
}

也就可以這麼來看,我們有幾套本地化資源,他們通過 Name 來進行標識,如果你需要在本地化管理器獲取某一套本地化資源,那麼你可以直接通過 Name 來進行定位。而每一套本地化資源,自身都擁有具體的多語言數據,這些多語言數據有可能來自文件也有可能來自資料庫,這取決於你具體的實現。

2.4.3 基於字典的本地化資源

最開始我們在使用範例當中,通過 DictionaryBasedLocalizationSource 來建立我們的本地化資源對象。該對象實現了 ILocalizationSourceIDictionaryBasedLocalizationSource 介面,內部定義了一個本地化資源字典提供器。

當調用本地化資源的 Initialize() 方法的時候,會使用具體的本地化資源字典提供器來獲取數據,而這個字典提供器可以為 XmlFileLocalizationDictionaryProviderJsonEmbeddedFileLocalizationDictionaryProvider 等。

這些內部字典提供器在初始化的時候,會將自身的數據按照 語言/多語言項 的形式將多語言信息存放在一個字典之中,而這個字典又可以分為 XML、JSON 等等等等...

// 內部字典提供器
public interface ILocalizationDictionaryProvider
{
    // 語言/多語言項字典
    IDictionary<string, ILocalizationDictionary> Dictionaries { get; }

    // 本地化資源初始化時被調用
    void Initialize(string sourceName);
}

而這裡的 ILocalizationDictionary 其實就是一個鍵值對,鍵關聯的是多語言項的標識 KEY,例如 "Home",而 Value 就是具體的展示文本信息了。

而是用字典本地化資源對象獲取數據的時候,其實也就是從其內部的字典提供器來獲取數據。

例如本地化資源有一個 GetString() 方法,它內部擁有一個字典提供器 DictionaryProvider,我要獲取某個 KEY 為 "Home" 所需要經過的步驟如下。

public ILocalizationDictionaryProvider DictionaryProvider { get; }

public string GetString(string name)
{
    // 獲取當前用戶區域文化,標識為 "Home" 的展示文本
    return GetString(name, CultureInfo.CurrentUICulture);
}

public string GetString(string name, CultureInfo culture)
{
    // 獲取值
    var value = GetStringOrNull(name, culture);

    // 判斷值為空的話,根據配置的要求是否拋出異常
    if (value == null)
    {
        return ReturnGivenNameOrThrowException(name, culture);
    }

    return value;
}

// 獲得 KEY 關聯的文本
public string GetStringOrNull(string name, CultureInfo culture, bool tryDefaults = true)
{
    var cultureName = culture.Name;
    var dictionaries = DictionaryProvider.Dictionaries;

    // 在這裡就開始從初始化所載入完成的語言字典裡面,獲取具體的多語言項字典
    ILocalizationDictionary originalDictionary;
    if (dictionaries.TryGetValue(cultureName, out originalDictionary))
    {
        // 多語言項字典拿取具體的多語言文本值
        var strOriginal = originalDictionary.GetOrNull(name);
        if (strOriginal != null)
        {
            return strOriginal.Value;
        }
    }

    if (!tryDefaults)
    {
        return null;
    }

    //Try to get from same language dictionary (without country code)
    if (cultureName.Contains("-")) //Example: "tr-TR" (length=5)
    {
        ILocalizationDictionary langDictionary;
        if (dictionaries.TryGetValue(GetBaseCultureName(cultureName), out langDictionary))
        {
            var strLang = langDictionary.GetOrNull(name);
            if (strLang != null)
            {
                return strLang.Value;
            }
        }
    }

    //Try to get from default language
    var defaultDictionary = DictionaryProvider.DefaultDictionary;
    if (defaultDictionary == null)
    {
        return null;
    }

    var strDefault = defaultDictionary.GetOrNull(name);
    if (strDefault == null)
    {
        return null;
    }

    return strDefault.Value;
}

2.3.4 基於資料庫的本地化資源

如果你有集成 Abp.Zero 模塊的話,可以通過在啟動模塊的預載入方法編寫以下代碼啟用 Zero 的多語言機制。

Configuration.Modules.Zero().LanguageManagement.EnableDbLocalization();

Abp.Zero 針對原有的本地化資源進行了擴展,新增的本地化資源類叫做 MultiTenantLocalizationSource,該類同語言管理器一樣,是一個基於多租戶實現的本地化資源,內部字典的值是從資料庫當中獲取的,其大體邏輯與字典本地化資源一樣,都是內部維護有一個字典提供器。

在通過 EnableDbLocalization() 方法的時候就直接替換掉了 ILanguageProvider 的預設實現,並且在配置的 Sources 源裡面也增加了 MultiTenantLocalizationSource 作為一個本地化資源。

2.5 本地化資源管理器

扯了這麼多,讓我們來看一下最為核心的 ILocalizationManager 介面,如果我們需要獲取某個數據源的某個 Key 所對應的多語言值肯定是要註入這個本地化資源管理器來進行操作的。

public interface ILocalizationManager
{
    // 根據名稱獲得本地化數據源
    ILocalizationSource GetSource(string name);

    // 獲取所有的本地化數據源
    IReadOnlyList<ILocalizationSource> GetAllSources();
}

這裡的數據源標識的就是一個命名空間的作用,比如我在 A 模塊當中有一個 Key 為 "Home" 的多語言項,在 B 模塊也有一個 Key 為 "Home" 的多語言項,這個時候就可以用數據源標識來區分這兩個 "Home"

本地化資源管理器通過在初始化的時候調用其 Initialize() 來初始化所有被註入的本地化資源,最後並將其放在一個字典之中,以便後續使用。

private readonly IDictionary<string, ILocalizationSource> _sources;

foreach (var source in _configuration.Sources)
{
    // ... 其他代碼
    _sources[source.Name] = source;
    source.Initialize(_configuration, _iocResolver);
    
    // ... 其他代碼
}

3.結語

針對 Abp 的多語言處理本篇文章不太適合作為入門瞭解,其中大部分知識需要結合 Abp 源碼進行閱讀才能夠加深理解,此文僅作拋磚引玉之用,如有任何意見或建議歡迎大家在評論當中指出。

4.點此跳轉到總目錄


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

-Advertisement-
Play Games
更多相關文章
  • 系列目錄 一. 創建項目並集成swagger 1.1 創建 1.2 完善 二. 搭建項目整體架構 三. 集成輕量級ORM框架——SqlSugar 3.1 搭建環境 3.2 實戰篇:利用SqlSugar快速實現CRUD 3.3 生成實體類 四. 集成JWT授權驗證 五. 實現CORS跨域 六. 集成泛 ...
  • 併發編程的術語 併發 同時做多件事情 多線程 併發的一種形式,它採用多個線程來執行程式。 多線程是併發的一種形式,但不是唯一的形式。 並行處理 把正在執行的大量的任務分割成小塊,分配給多個同時運行的線程。 並行處理是多線程的一種,而多線程是併發的一種。 非同步編程 併發的一種形式,它採用future模 ...
  • 更新內容,v4.2.2版本:1.增加Modbus協議讀取多個寄存器,並且按多種數據類型解析數據。2.Modbus Serial和Modbus TCP兩個驅動合併成一個驅動。3.修改資料庫結構,保存配置信息。4.優化ServerSuperIO核心代碼,應用過程中的潛在問題。 v4.2.2 下載地址:官 ...
  • [TOC] 一、前言 筆者最近在做一個項目,項目中為了提升吞吐量,使用了消息隊列,中間實現了 生產消費模式 ,在生產消費者模式中需要有一個集合,來存儲生產者所生產的物品,筆者使用了最常見的 集合類型。 由於生產者線程有很多個,消費者線程也有很多個,所以不可避免的就產生了線程同步的問題。開始筆者是使用 ...
  • 轉載請註明出處: https://www.cnblogs.com/zhiyong-ITNote/ DI的大概過程抽象成如下:介面對象 <-- 實現對象 <-- 抽象對象 在抽象對象中引入介面,通過實例化介面對象來調用實現對象的方法或是成員變數。那麼就需要實現或者生成抽象對象,一般在已有的IOC框架或 ...
  • 一、面向對象(OOP) 面向過程 面向過程就是分析出解決問題的所需要的步驟,然後每個步驟使用函數實現,使用時將函數依次調用即可 C語言 面向對象 對象:生活中真實存在的事物(電腦、手機、草、樹......) 面向對象是把構成問題的事物分解成各個對象,建立對象的目的不是完成步驟,而是為了描述某個對象在 ...
  • 1. 設置 -> 頁首Html代碼,加入如下代碼,並保存: <script src="http://latex.codecogs.com/latex.js" type="text/javascript"></script> 2. 採用latex線上編輯公式,網站為http://www.codecog ...
  • 在理清 "路由" 的工作流程後,接下來需要考慮的,是MVC框架如何生成Controller以及它的生成時機。 根據以前ASP.NET MVC的經驗,Controller應該是由一個ControllerFactory構建的。查看ASP.NET Core MVC的源碼,果然是有一個DefaultCont ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...