Asp.Net Core 2.1发布后,正式支持System.Drawing.Common绘图了,可以用来做一些图片验证码之类的功能。但是把网站部署到docker容器里运行会遇到很多问题,也是非常闹心的,本文记录这些问题,希望帮到有需要的人。

创建网站

前提条件:安装最新版VS2017和Net Core SDK 2.1。

首先新建网站,选择Asp.Net Core 2.1 Web应用程序(模型视图控制器),不勾选docker,我习惯自行编写Dockerfile。

指定网站访问端口5000。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
//必须指定端口,否则在Win10命令行运行端口是5000,在CentOS docker运行端口是80
.UseUrls("http://*:5000")
.UseStartup<Startup>();

  

为了调试方便,把隐私要求和https要求先屏蔽。

public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
//options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
}); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
} public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
//app.UseHsts();
} //app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy(); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}

  

修改appsettings.json输出全部调试信息,便于查找错误。

{
"Logging": {
"LogLevel": {
"Default": "Debug"
}
},
"AllowedHosts": "*"
}

  

调试运行一下,确认网站没问题。

把Home控制器的Index页面改一下,简单粗暴一点,就显示一个图片好了。

@{
ViewData["Title"] = "Home Page";
} <h4>System.Drawing.Common绘图</h4>
<img src="Home/GetImg" alt="pic" class="img-thumbnail" width="400" height="200" />

  

NuGet安装System.Drawing.Common。

给Home控制器增加一个绘图函数GetImg。

public IActionResult GetImg()
{
_logger.LogInformation($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff}, start create image"); string msg = $"{DateTime.Now:HH:mm:ss}, 您好 drawing from .NET Core"; Image image = new Bitmap(400, 200);
Graphics graph = Graphics.FromImage(image);
graph.Clear(Color.Azure);
Pen pen = new Pen(Brushes.Black);
graph.DrawLines(pen, new Point[] { new Point(10, 10), new Point(380, 180) });
graph.DrawString(msg, new Font(new FontFamily("微软雅黑"), 12, FontStyle.Bold), Brushes.Blue, new PointF(10, 90)); //把图片保存到内存文件流
MemoryStream ms = new MemoryStream();
image.Save(ms, ImageFormat.Png); ;
byte[] buf = ms.GetBuffer(); _logger.LogInformation($"{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff}, finish create image"); return File(buf, "image/png");
}

  

调试运行一下,是没问题的。

部署网站到docker

编写Dockerfile,注意把文件属性“复制到输出目录”设置为“如果较新则复制”。

FROM microsoft/dotnet:2.1-aspnetcore-runtime
WORKDIR /app
COPY . /app
EXPOSE 5000
ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

重新编译网站,以文件夹方式发布到默认的bin\Release\PublishOutput。在Windows控制台进入发布目录,输入dotnet NetCoreDraw.dll运行网站,浏览器访问http://localhost:5000/,确认没问题。

编写docker-compose.yml

version: '3'

services:

  myweb:
container_name: myweb
image: mywebimage
build:
context: ./PublishOutput
dockerfile: Dockerfile
ports:
- "5000:5000"
environment:
- ASPNETCORE_ENVIRONMENT=Production
- TZ=Asia/Shanghai
restart: always

  

我用CentOS 7.3虚拟机做试验,安装好docker环境,用Xshell访问虚拟机,用Xftp把PublishOutput文件夹、docker-compose.yml拖到Home下面。

进入Home目录,把容器跑起来。

[root@localhost home]# docker-compose up
Creating network "home_default" with the default driver
Building myweb
Step 1/5 : FROM microsoft/dotnet:2.1-aspnetcore-runtime
2.1-aspnetcore-runtime: Pulling from microsoft/dotnet
be8881be8156: Pull complete
f854db899319: Pull complete
4591fd524b8e: Pull complete
65f224da8749: Pull complete
Digest: sha256:a43b729b84f918615d4cdce92a8bf59e3e4fb2773b8491a7cf4a0d728886eeba
Status: Downloaded newer image for microsoft/dotnet:2.1-aspnetcore-runtime
---> fcc3887985bb
Step 2/5 : WORKDIR /app
Removing intermediate container aba36715acfc
---> 25bc5bb6871f
Step 3/5 : COPY . /app
---> 9baaa790a82f
Step 4/5 : EXPOSE 5000
---> Running in 269408c67989
Removing intermediate container 269408c67989
---> fbd444c44d20
Step 5/5 : ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]
---> Running in 2a9ba559b137
Removing intermediate container 2a9ba559b137
---> b1bb1dccd49a
Successfully built b1bb1dccd49a
Successfully tagged mywebimage:latest
WARNING: Image for service myweb was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating myweb ... done
Attaching to myweb
myweb | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
myweb | No XML encryptor configured. Key {1f87d27e-c6b1-435f-bab6-aebacd6d6817} may be persisted to storage in unencrypted form.
myweb | Hosting environment: Production
myweb | Content root path: /app
myweb | Now listening on: http://[::]:5000
myweb | Application started. Press Ctrl+C to shut down.

  

在浏览器访问我的虚拟机里的网站http://192.168.41.129:5000/,图片显示不出来。

在Xshell可以看到容器调试信息,发生了错误。

myweb    |       2018-07-29 09:50:04:753, start create image
myweb | info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
myweb | Executed action NetCoreDraw.Controllers.HomeController.GetImg (NetCoreDraw) in 18.5988ms
myweb | fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
myweb | An unhandled exception has occurred while executing the request.
myweb | System.TypeInitializationException: The type initializer for 'Gdip' threw an exception. ---> System.DllNotFoundException: Unable to load shared library 'libdl' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibdl: cannot open shared object file: No such file or directory
myweb | at Interop.Libdl.dlopen(String fileName, Int32 flag)
myweb | at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary()
myweb | at System.Drawing.SafeNativeMethods.Gdip..cctor()
myweb | --- End of inner exception stack trace ---

  

找不到库文件libdl,网上有类似的问题和解决方案,就是建立一个文件连接。

https://q.cnblogs.com/q/107946/

但是aspnetcore容器中的库文件位置,跟正式发行版本的CentOS和Ubuntu不太一样,得进入容器去找。在容器运行的时候,通过Xshell的复制功能,再开一个终端窗口,进入容器。

docker exec -it myweb /bin/bash

aspnetcore容器不支持locate命令,我对Linux系统文件位置不熟,只好硬着头皮挨个看了一遍,还好目录不多,最后确定在这里。

root@544f7be29f68:/# ls lib/x86_64-linux-gnu/libdl*

lib/x86_64-linux-gnu/libdl-2.24.so  lib/x86_64-linux-gnu/libdl.so.2

所以修改Dockerfile为

FROM microsoft/dotnet:2.1-aspnetcore-runtime

RUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.so

WORKDIR /app
COPY . /app
EXPOSE 5000
ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

重新编译、发布网站到虚拟机,重新运行编译运行容器。

[root@localhost home]# docker-compose up --build

浏览网站,仍然无法显示图片,但是错误内容变了。

myweb    | fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
myweb | An unhandled exception has occurred while executing the request.
myweb | System.TypeInitializationException: The type initializer for 'Gdip' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'libgdiplus': The specified module could not be found.
myweb | at System.Runtime.InteropServices.FunctionWrapper`1.get_Delegate()
myweb | at System.Drawing.SafeNativeMethods.Gdip.GdiplusStartup(IntPtr& token, StartupInput& input, StartupOutput& output)
myweb | at System.Drawing.SafeNativeMethods.Gdip..cctor()
myweb | --- End of inner exception stack trace ---

  

这次是找不到libgdiplus,网上也有关于这个问题的解决方案。

https://q.cnblogs.com/q/103863/

因为需要在容器跑起来的时候安装一些东西,所以要更换为国内的源,提高速度。参考

https://www.cnblogs.com/OMango/p/8519980.html

把Dockerfile改为这样了,注意更新源之后要apt-get update一下,否则会报错Unable to locate package libgdiplus。

FROM microsoft/dotnet:2.1-aspnetcore-runtime

RUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.so

RUN echo "deb http://mirrors.aliyun.com/debian wheezy main contrib non-free \
deb-src http://mirrors.aliyun.com/debian wheezy main contrib non-free \
deb http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free \
deb-src http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free \
deb http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free \
deb-src http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free" > /etc/apt/sources.list RUN apt-get update
RUN apt-get install libgdiplus -y && ln -s libgdiplus.so gdiplus.dll WORKDIR /app
COPY . /app
EXPOSE 5000
ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

再次运行,终于看到图片了,但是汉字没有显示出来。

参考上面的文章,把字体文件复制到容器中,再安装字体相关的功能即可。最终Dockerfile长这样。

FROM microsoft/dotnet:2.1-aspnetcore-runtime

RUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.so

RUN echo "deb http://mirrors.aliyun.com/debian wheezy main contrib non-free \
deb-src http://mirrors.aliyun.com/debian wheezy main contrib non-free \
deb http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free \
deb-src http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free \
deb http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free \
deb-src http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free" > /etc/apt/sources.list RUN apt-get update
RUN apt-get install libfontconfig1 -y
RUN apt-get install libgdiplus -y && ln -s libgdiplus.so gdiplus.dll COPY ./fonts/msyh.ttc /usr/share/fonts/dejavu WORKDIR /app
COPY . /app
EXPOSE 5000
ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

把Win10的微软雅黑字体文件msyh.ttc放到项目的fonts目录下,设置文件属性“复制到输出目录”设置为“如果较新则复制”。

再次运行容器,搞定了。

Asp.Net Core网站跨平台部署到Linux容器运行是一个飞跃性的技术进步,但是时不时会碰到一些跟Linux系统相关的问题,总感觉是又爱又恨,心太累。

源代码

https://github.com/woodsun2018/NetCoreDraw

Asp.Net Core使用System.Drawing.Common部署到docker报错问题的更多相关文章

  1. .Net Core 使用 System.Drawing.Common 在CentOS下报错

    .Net Core控制台项目,添加了 System.Drawing.Common 引用 #locate libdl /usr/lib64/libdl-2.17.so /usr/lib64/libdl. ...

  2. .Net Core 使用 System.Drawing.Common 部署到CentOS上遇到的问题

    一开始报这个错误:Unable to load shared library 'libdl' 找到libdl安装位置是/usr/lib64: #locate libdl /usr/lib64/libd ...

  3. asp.net core 2.0发布到IIS流程及报错解决方案

      我这是个新装的服务器,没有安装任何软件. 一.发布流程 1.安装AspNetCoreModule托管模块,同时会自动安装..net core runtime DotNetCore.2.0.8-Wi ...

  4. .NET Core System.Drawing.Common 中文乱码的坑

    最近在写一个汉字取点阵的程序,最开始是在win环境下运行的,没发现什么异常,然后今天把程序放在centos 下后发现英文正常,中文完全变成两位的字了,最开始是字体的原因 在把宋体等安装到centos ...

  5. [亲测]ASP.NET Core 2.0怎么发布/部署到Ubuntu Linux服务器并配置Nginx反向代理实现域名访问

    前言 ASP.NET Core 2.0 怎么发布到Ubuntu服务器?又如何在服务器上配置使用ASP.NET Core网站绑定到指定的域名,让外网用户可以访问呢? 步骤 第1步:准备工作 一台Liun ...

  6. ASP.NET Core 共享第三方依赖库部署的正常打开方式

    曾经: 写了一篇: ASP.Net Core on Linux (CentOS7) 共享第三方依赖库部署 当第二次想做相同的事,却遇上了Bug,于是有了第二篇: ASP.NET Core 共享第三方依 ...

  7. [亲测]七步学会ASP.NET Core 2.0怎么发布/部署到Ubuntu Linux服务器并配置Nginx反向代理实现域名访问

    前言 ASP.NET Core 2.0 怎么发布到Ubuntu服务器?又如何在服务器上配置使用ASP.NET Core网站绑定到指定的域名,让外网用户可以访问呢? 步骤 第1步:准备工作 一台Liun ...

  8. 在linux 或docker中使用 system.drawing.common

    在dockerfile 中添加 FROM microsoft/dotnet:2.1-aspnetcore-runtime RUN apt-get update RUN apt-get install ...

  9. Linux/Docker 中使用 System.Drawing.Common 踩坑小计

    前言 在项目迁移到 .net core 上面后,我们可以使用 System.Drawing.Common 组件来操作 Image,Bitmap 类型,实现生成验证码.二维码,图片操作等功能.Syste ...

随机推荐

  1. web的脚本安全-XSS

    XSS,即Cross Site Scripting,叫X是因为之前有了一个CSS.中文可以叫跨站脚本攻击.是前端工程师的一大威胁. XSS的根本,就是有恶意用户把代码植入了你要访问的页面中,从而控制你 ...

  2. php -- 4种嵌入标记

    ----- 001-tags.php ----- <!DOCTYPE html> <html> <head> <meta http-equiv="c ...

  3. JavaScript -- History

    -----042-History.html----- <!DOCTYPE html> <html> <head> <meta http-equiv=" ...

  4. vue实现城市列表选择

    成果展示 最后的成果就是下面所展示的内容,因为gif图没有做,只能截图所展示,接下来,会带着大家一步一步的完成下面功能,脚手架搭建和node安装在本次案例不会讲解,如果了解,可以在我的博客园找到有详细 ...

  5. java入门,学习笔记

    编译 通过javac编译java程序,会编译出一个后缀为class的文件,我们再通过java虚拟机(jvm)执行编译后的java程序. 在java中始终有一个main函数,它作为程序的入口,程序从这个 ...

  6. Sublime Text shift+ctrl 妙用

    1 :按住shift+ctrl然后按←或→可快速选中一行中的某一部分,相当于双击鼠标选中. 当你想在代码末尾加注释的话,这个方法很好用 输入文字 -> 光标移到文字末尾 -> 按住shif ...

  7. Linux下解决高并发socket最大连接数限制,tcp默认1024个连接

    linux作为服务器系统,当socket运行高并发TCP程序时,通常会出现连接建立到一定个数后不能再建立连接的情况 本人在工作时,测试高并发tcp程序(GPS服务器端程序),多次测试,发现每次连接建立 ...

  8. 一次Linux服务器被入侵和删除木马程序的经历

    转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://wzlinux.blog.51cto.com/8021085/1740113 一.背景 晚上看到有台服 ...

  9. SSL编程(2).NET最简单的客户端

      在Windows平台上,实现SSL的.NET类是System.Net.Security.SslStream类.这个类既可以用于建立SSL服务,也可以用来作为SSL客户端连接远端的SSL服务. 最简 ...

  10. UVa Dropping Balls

    题目链接: https://cn.vjudge.net/problem/UVA-679 /* 问题 输入完全二叉树的层数D和有几个小球滚落,计算最后一个小球落入的叶子结点的小号. 解题思路 直接模拟超 ...