Asp.Net Core使用System.Drawing.Common部署到docker報錯問題

來源:互聯網
上載者:User

標籤:control   setting   user   tac   wheezy   重新編譯   shu   tin   docke   

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-runtimeWORKDIR /appCOPY . /appEXPOSE 5000ENTRYPOINT ["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目錄,把容器跑起來。

[[email protected] home]# docker-compose upCreating network "home_default" with the default driverBuilding mywebStep 1/5 : FROM microsoft/dotnet:2.1-aspnetcore-runtime2.1-aspnetcore-runtime: Pulling from microsoft/dotnetbe8881be8156: Pull completef854db899319: Pull complete4591fd524b8e: Pull complete65f224da8749: Pull completeDigest: sha256:a43b729b84f918615d4cdce92a8bf59e3e4fb2773b8491a7cf4a0d728886eebaStatus: Downloaded newer image for microsoft/dotnet:2.1-aspnetcore-runtime ---> fcc3887985bbStep 2/5 : WORKDIR /appRemoving intermediate container aba36715acfc ---> 25bc5bb6871fStep 3/5 : COPY . /app ---> 9baaa790a82fStep 4/5 : EXPOSE 5000 ---> Running in 269408c67989Removing intermediate container 269408c67989 ---> fbd444c44d20Step 5/5 : ENTRYPOINT ["dotnet", "NetCoreDraw.dll"] ---> Running in 2a9ba559b137Removing intermediate container 2a9ba559b137 ---> b1bb1dccd49aSuccessfully built b1bb1dccd49aSuccessfully tagged mywebimage:latestWARNING: 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 ... doneAttaching to mywebmyweb    | 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: Productionmyweb    | Content root path: /appmyweb    | Now listening on: http://[::]:5000myweb    | 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 imagemyweb    | info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]myweb    |       Executed action NetCoreDraw.Controllers.HomeController.GetImg (NetCoreDraw) in 18.5988msmyweb    | 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 directorymyweb    |    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系統檔案位置不熟,只好硬著頭皮挨個看了一遍,還好目錄不多,最後確定在這裡。

[email protected]:/# 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-runtimeRUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.soWORKDIR /appCOPY . /appEXPOSE 5000ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

重新編譯、發布網站到虛擬機器,重新運行編譯運行容器。

[[email protected] 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-runtimeRUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.soRUN 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.listRUN apt-get updateRUN apt-get install libgdiplus -y && ln -s libgdiplus.so gdiplus.dllWORKDIR /appCOPY . /appEXPOSE 5000ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

再次運行,終於看到圖片了,但是漢字沒有顯示出來。

參考上面的文章,把字型檔複製到容器中,再安裝字型相關的功能即可。最終Dockerfile長這樣。

FROM microsoft/dotnet:2.1-aspnetcore-runtimeRUN ln -s /lib/x86_64-linux-gnu/libdl-2.24.so /lib/x86_64-linux-gnu/libdl.soRUN 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.listRUN apt-get updateRUN apt-get install libfontconfig1 -yRUN apt-get install libgdiplus -y && ln -s libgdiplus.so gdiplus.dllCOPY ./fonts/msyh.ttc /usr/share/fonts/dejavuWORKDIR /appCOPY . /appEXPOSE 5000ENTRYPOINT ["dotnet", "NetCoreDraw.dll"]

  

把Win10的微軟雅黑字型檔msyh.ttc放到項目的fonts目錄下,設定檔案屬性“複製到輸出目錄”設定為“如果較新則複製”。

再次運行容器,搞定了。

Asp.Net Core網站跨平台部署到Linux容器運行是一個飛躍性的技術進步,但是時不時會碰到一些跟Linux系統相關的問題,總感覺是又愛又恨,心太累。

Asp.Net Core使用System.Drawing.Common部署到docker報錯問題

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.