日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

解决 .NET Core 在 Linux Container 中获取 CurrentCulture 不正确的问题

發(fā)布時間:2023/12/4 linux 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解决 .NET Core 在 Linux Container 中获取 CurrentCulture 不正确的问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

背景

在將公司一款基于 .NET Framework 的控制臺程序遷移到 .NET Core 3.1 時,發(fā)現(xiàn)程序中本地化的部分失效,癥狀類似于對?Thread.CurrentThread.CurrentCulture.Name?的值進(jìn)行?Substring()?操作時拋出?ArgumentOutOfRangeException?異常。

該程序在 Windows Container 中工作良好,遷移為 .NET Core 后在我的 Windows 開發(fā)機上也運行良好,一旦部署到 K8s 的 Linux 容器中就會出現(xiàn)問題。容器使用的是基于微軟官方的 .NET Runtime 3.1 鏡像(https://hub.docker.com/_/microsoft-dotnet-runtime/)。

本文按我當(dāng)時解決此問題的思路記錄,從 Windows 開始,挨個環(huán)境測試?CurrentThread.CurrentCulture。


TL;DR 先上結(jié)論

.NET Core Runtime 的 Linux 鏡像沒有設(shè)置語言信息,導(dǎo)致通過?CurrentThread.CurrentCulture?獲取的?Name?為?String.Empty。

只需要在生成鏡像時為 Linux 設(shè)置語言即可,本文末尾附有解決方案。

在 Windows 中獲取區(qū)域設(shè)置

先創(chuàng)建一個名為?CultureTest?的控制臺項目看看效果,這里使用 .NET Core 的 LTS 版本 .NET Core 3.1 為例,通過命令行執(zhí)行:

dotnet new console -o CultureTest --framework netcoreapp3.1

然后進(jìn)入?CultureTest?文件夾,將生成的?Program.cs?替換為如下內(nèi)容:

using System; using System.Globalization; using System.Linq; using System.Threading;namespace CultureTest {class Program{static void Main(){PrintProperty(Thread.CurrentThread.CurrentCulture);Thread.Sleep(TimeSpan.FromDays(1));}private static void PrintProperty(CultureInfo cultureInfo){var printableProperties = cultureInfo.GetType().GetProperties().Where(p => p.PropertyType.IsValueType || p.PropertyType == typeof(string));foreach (var property in printableProperties){Console.WriteLine($"{property.Name}: {property.GetValue(cultureInfo)}");}}} }
  • PrintProperty()?方法主要用途是將?CultureInfo?類中所有值類型和?string?類型的屬性找到,并將我們傳入的?Thread.CurrentThread.CurrentCulture?對象的這些屬性值都打印出來。

  • Thread.Sleep()?是為在后面測試 docker 時用于防止程序運行后直接退出之用。

我在一臺區(qū)域設(shè)置為?中文(簡體,中國)?的 Windows 10 PC 上運行上述代碼:

dotnet run

可以看見?Name?為?zh-CN?和 Windows 一致。
查看信息后,由于有?Thread.Sleep()?的邏輯,需要通過?Ctrl + C?來停止程序的運行(后面 Linux 和 Docker 中也一樣)。


在 Linux 中獲取區(qū)域信息

我在 WSL(https://docs.microsoft.com/windows/wsl/install-win10) 中安裝了 Debian 10,并安裝了 .NET Core 3.1 SDK,下面用 Debian 來進(jìn)行測試。


locale 命令

在 Linux 中,可以使用?locale?命令查看當(dāng)前語言環(huán)境信息:

locale

關(guān)注?LANG?的值,現(xiàn)在顯示為?en_US.UTF-8。

locale?命令加上?-a?選項后可以查看可用的語言環(huán)境信息:

locale -a

可以看到這個 Debian 除了當(dāng)前的?en_US.UTF-8,還支持其它幾種語言環(huán)境。


通過 CurrentThread 獲取

由于是 WSL,可以通過?/mnt?中掛載的 Windows 文件系統(tǒng),直接導(dǎo)航到上一節(jié)創(chuàng)建的項目中,并運行:

cd /mnt/d/projects/CultureTest dotnet run

可以看見?Name?為?en-US?和?locale?命令得到的一致。


在 Docker 容器中獲取區(qū)域信息

下面將測試程序放入容器中運行。

發(fā)布測試程序

先發(fā)布?CultureTest?項目:

dotnet publish -c Release

默認(rèn)會發(fā)布到?.\bin\Release\netcoreapp3.1\publish\?文件夾下,可以使用?dir(Windows) 或?ls(Linux) 命令查看發(fā)布結(jié)果。


創(chuàng)建 Dockerfile

接下來為?CultureTest?生成鏡像。

首先在?CultureInfo?項目根目錄(.csproj?所在的目錄)下創(chuàng)建?Dockerfile?并填入以下內(nèi)容:

FROM mcr.microsoft.com/dotnet/runtime:3.1COPY ./bin/Release/netcoreapp3.1/publish/ /app/ WORKDIR /app ENTRYPOINT ["dotnet", "CultureTest.dll"]

這里使用 .NET Core 官方提供的?.NET Runtime 鏡像?mcr.microsoft.com/dotnet/runtime:3.1?作為 Runtime

  • 拷貝剛剛發(fā)布到?.\bin\Release\netcoreapp3.1\publish\?的程序到容器的?/app?文件夾下

  • 將容器的工作目錄設(shè)為?/app?文件夾

  • 通過?dotnet CultureTest.dll?命令運行測試項目


生成鏡像

在?Dockerfile?所在的目錄下執(zhí)行?docker build?命令生成鏡像:

docker build -t culture-test .
  • -t culture-test?設(shè)置鏡像的名稱為?culture-test

  • 不要漏掉最后的?.


運行并查看結(jié)果

通過上一步創(chuàng)建的?culture-test?鏡像生成一個容器,并查看執(zhí)行結(jié)果:

docker run culture-test

發(fā)現(xiàn)?Name?后沒有任何內(nèi)容。

經(jīng)過測試,CurrentThread.CurrentCulture?不會為?null,并且?Name?屬性的值為?String.Empty?而非?null。這也是我遇到問題的原因,對?String.Empty?進(jìn)行了?Substring()?操作,所以拋出了?ArgumentOutOfRangeException?異常,問題重現(xiàn)。


在容器中執(zhí)行 locale

進(jìn)入容器,查看 Linux 的語言環(huán)境信息:

docker run -d culture-test docker exec -it [your_container_id] /bin/bash
  • 通過?-d?讓程序后臺運行(有?Thread.Sleep()?在,所以程序不會退出,這樣我們就能進(jìn)入到容器內(nèi)執(zhí)行命令),這一步執(zhí)行后會返回容器 id

  • 通過?exec?執(zhí)行容器里的?/bin/bash

發(fā)現(xiàn)?locale?命令返回的?LANG?也是空白的。

并且?locale -a?命令返回的?C?和?POSIX?都是默認(rèn)不含語言的環(huán)境。


原因

如果使用過 Linux 的 GUI 安裝 Linux,一般會讓選擇語言和地區(qū),但?mcr.microsoft.com/dotnet/runtime:3.1?以及它基于的?Debian?鏡像(https://github.com/dotnet/dotnet-docker/blob/87cbc30052e5dc892313122e26364b5051df905b/src/runtime-deps/3.1/buster-slim/amd64/Dockerfile),都沒有設(shè)置語言,所以導(dǎo)致我們通過?locale?或是 C# 的?CurrentThread.CurrentCulture?獲取到的都是空白的內(nèi)容。

那么結(jié)合上面的信息,要想讓依賴于區(qū)域語言信息的程序不報錯,有兩種方案:

  • 修改程序,增加對?CurrentCulture.Name?的判斷:如果?CurrentCulture.Name == String.Empty,則為程序設(shè)置一個默認(rèn) Culture

  • 修改運行環(huán)境,將默認(rèn)語言信息設(shè)置為需要的值(例如?en-US)


為容器中的 Linux 設(shè)置語言信息

雖然最后我選擇的是修改程序,但也來了解一下這種情況如何為容器中的 Linux 設(shè)置語言信息。

通過搜索,找到了 StackOverflow 上的提問:How to set the locale inside a Debian/Ubuntu Docker container?(https://stackoverflow.com/questions/28405902/how-to-set-the-locale-inside-a-debian-ubuntu-docker-container),并從中得到了解決方案。

方案一:通過安裝 locales-all 包

通過安裝?locales?和?locales-all?包,可以把所有支持的語言信息都安裝到系統(tǒng)中,再通過環(huán)境變量設(shè)置需要的語言。

修改?Dockerfile:

FROM mcr.microsoft.com/dotnet/runtime:3.1# 安裝所有支持的語言信息,并設(shè)置 en_US.UTF-8 為當(dāng)前語言 RUN apt-get update RUN apt-get install -y locales locales-all ENV LANG en_US.UTF-8COPY ./bin/Release/netcoreapp3.1/publish/ /app/ WORKDIR /app ENTRYPOINT ["dotnet", "CultureTest.dll"]


方案二:通過安裝 locales 包,并修改 locale.gen 文件

修改?Dockerfile:

FROM mcr.microsoft.com/dotnet/runtime:3.1# 安裝 locales 包,并修改 locale.gen 文件,再設(shè)置語言 RUN apt-get update RUN apt-get install -y locales RUN sed -i -e '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen ENV LANG en_US.UTF-8 COPY ./bin/Release/netcoreapp3.1/publish/ /app/ WORKDIR /app ENTRYPOINT ["dotnet", "CultureTest.dll"]

安裝?locales?后,會生成?/etc/locale.gen?文件,文件內(nèi)容類似于:

# en_SG ISO-8859-1 # en_SG.UTF-8 UTF-8 # en_US ISO-8859-1 # en_US.ISO-8859-15 ISO-8859-15 # en_US.UTF-8 UTF-8 # en_ZA ISO-8859-1 # en_ZA.UTF-8 UTF-8 # en_ZM UTF-8 # en_ZW ISO-8859-1 # en_ZW.UTF-8 UTF-8

通過?sed?命令:

  • /en_US.UTF-8:將包含?en_US.UTF-8?字樣的行

  • /s:執(zhí)行替換

  • /^#:將行首的?#

  • /:替換為空白

然后執(zhí)行?locale-gen?命令并設(shè)置?LANG?的值為?en_US.UTF-8。

這兩種方式都能確保?CurrentThread.CurrentCulture?獲取到正確的 Culture Name。

總結(jié)

以上是生活随笔為你收集整理的解决 .NET Core 在 Linux Container 中获取 CurrentCulture 不正确的问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。