背景:
最近我有一个项目中有生成二维码图片的需求,我用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库