背景:
最近我有一個項目中有生成二維碼圖片的需求,我用Gma.QrCodeNet.Core組件實現,在Window系統上運行一切都是正常的,發布到測試環境CentOS系統后這個接口拋出System.TypeInitializationException:The type initializer for 'Gdip' threw an exception -->System.DllNotFoundException:Unable to load DLL 'libgdiplus' ; The specified module could not be found. 這個錯誤是在初始化Gdip時出現異常,原因時沒有加載到libgdiplus 這個DLL。
知其所以然:
出現這個錯誤是因為Gma.QrCodeNet.Core組件依賴了微軟的System.Drawing.Common.dll庫,早期的.NET Core版本是沒有System.Drawing.Common.dll庫的,微軟在.NET Core3.0開始提供了這個庫,該庫封裝了GDI+繪圖功能。GDI 全名為:Graphics Device Interface(圖形設備接口),而GDI是屬於Windows系統下的圖形設備接口,那么.NET Core有沒有實現Linux系統下的“GDI”呢?答案是沒有。
當.NET還沒有實現跨平台的時候,mono團隊就替微軟.NET跨平台操碎了心,mono大量的應用在游戲行業,游戲開發者們既依賴微軟的unity3d開發庫,又不想使用臃腫低效且閉源的Windows系統。為了讓.NET代碼運行在Linux系統上,因此誕生了mono項目,大家都知道后來mono被微軟招安。而mono團隊后來實現了.NET Core在LinuxOS和MacOS系統下的DGI相關接口,他就是libgdiplus。因此System.Drawing.Common.dll庫在Windows系統下繼續調用原來的GDI實現,在MacOS和LinuxOS下則依賴libgdiplus來實現繪圖能力。
所以,我的項目在Window系統正常運行,在Linxu上則拋出System.TypeInitializationException:The type initializer for 'Gdip' threw an exception -->System.DllNotFoundException:Unable to load DLL 'libgdiplus' ; The specified module could not be found. 異常。要解決這個問題就很簡單了,只需要給Linux系統安裝libgdiplus庫就行了。
解決問題:
1.系統簡單通過dotnet XXXXX.dll命令直接運行在linux上,則直接在系統中安裝libgdiplus就可以了。
CentOS安裝命令:
yum install libgdiplus-devel -y ln -s /usr/lib64/libgdiplus.so /usr/lib/gdiplus.dll ln -s /usr/lib64/libgdiplus.so /usr/lib64/gdiplus.dll
Ubuntu安裝命令
sudo curl https://raw.githubusercontent.com/stulzq/awesome-dotnetcore-image/master/install/ubuntu.sh|sh
2.在Docker中運行的項目因為每次重新構建Docker鏡像原來的安裝就沒用了,所以有兩個方案,
第一個方案是基於微軟的鏡像把libgdiplus加入重新打包一個新的鏡像。以后重新部署項目都基於這個新的鏡像來構建。
第二個方案是每次部署項目構建鏡像時自動安裝libgdiplus庫。那么就需要將安裝libgdiplus庫的命令添加到Dockerfile文件中。Dockerfile文件內容如下:
FROM mcr.microsoft.com/dotnet/aspnet:5.0 MAINTAINER pudefu LABEL description="某某某項目" LABEL version="1.0" WORKDIR /app COPY . . # 切換apt源為網易 RUN echo "" > /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/debian/ stretch main non-free contrib" >> /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list \ && echo "deb-src http://mirrors.163.com/debian/ stretch main non-free contrib" >> /etc/apt/sources.list \ && echo "deb-src http://mirrors.163.com/debian/ stretch-updates main non-free contrib" >> /etc/apt/sources.list \ && echo "deb-src http://mirrors.163.com/debian/ stretch-backports main non-free contrib" >> /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/debian-security/ stretch/updates main non-free contrib" >> /etc/apt/sources.list \ && echo "deb-src http://mirrors.163.com/debian-security/ stretch/updates main non-free contrib" >> /etc/apt/sources.list
# 安裝gdiplus RUN apt-get update -y && apt-get install -y libgdiplus && apt-get clean && ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll EXPOSE 8888 RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone ENV ASPNETCORE_ENVIRONMENT Development #ENTRYPOINT ["dotnet","XXXXXX.dll"]
這里安裝libgdiplus庫只需要增加如下命令即可。
RUN apt-get update -y && apt-get install -y libgdiplus && apt-get clean && ln -s /usr/lib/libgdiplus.so /usr/lib/gdiplus.dll
但是libgdiplus庫原生提供地址下載太慢,至少正常人都不能忍受。所以我們需要將下載源修改為國內源,比如阿里,騰訊,網易等都可以。最開始我使用的是阿里雲的源,但是遇到鑒權相關問題,換了網易的源則沒有相關問題,騰訊的沒有測試。
至此,問題解決,又可以愉快的寫代碼了。
提示:System.Drawing.Common.dll庫

