在AWS Lambda使用System.Drawing.Common NuGet包时无法加载DLL 'libdl'。

23

我们有一个缩略图生成的 lambda 函数,我正在尝试将其更新为 .NET Core 2.0,但是在使用 Microsoft 的 System.Drawing.Common NuGet 包时遇到了以下错误:

TypeInitializationException

The type initializer for 'Gdip' threw an exception. at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(Int32 width, Int32 height, Int32 stride, Int32 format, HandleRef scan0, IntPtr& bitmap) at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format) at TestFailExample.Function.FunctionHandler(String input, ILambdaContext context) in C:\work\graphics\TestFailExample\Function.cs:line 25 at lambda_method(Closure , Stream , Stream , LambdaContextInternal )

这是由以下原因引起的:

DllNotFoundException

无法加载 DLL 'libdl':找不到指定的模块或其中的一个。 (HRESULT 异常:0x8007007E) at Interop.Libdl.dlopen(String fileName, Int32 flag) at System.Drawing.SafeNativeMethods.Gdip.LoadNativeLibrary() at System.Drawing.SafeNativeMethods.Gdip..cctor()

我看过这个问题,但没有解决方案。

复现此问题的最小代码如下:

public string FunctionHandler(string input, ILambdaContext context)
{
    using (var bmp = new Bitmap(100, 100))
    {
        return bmp.Width.ToString();
    }
}
只需创建一个.NET Core 2.0 Lambda函数项目,添加对"System.Drawing.Common" NuGet包的引用,然后将函数处理程序替换为上面的代码。将其放在AWS上并运行以获取错误。我注意到只有在尝试实际使用它时才会出现引用包不会导致问题,但这可能是由于编译器优化造成的。
我已将MCVE打包到项目中,并将其上传到GitHub here,为了简化人们重现问题所必须经历的步骤。
我可以看到"/lib64/libdl.so.2"存在,但"/lib64/libdl.so"不存在。由于符号链接似乎不可能(只读文件系统),我不确定如何解决此问题。我尝试使用LD_LIBRARY_PATH环境变量通过在/tmp中创建文件夹并将文件链接到那里作为函数执行的第一件事来解决。不幸的是,它似乎在这里查找所有库,因此函数根本不运行。我还尝试将LD_LIBRARY_PATH设置为"/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/tmp",虽然我现在可以再次运行函数,但这仍然没有帮助,我仍然收到相同的Gdip错误。
我注意到/var/task/lib已经包含在LD_LIBRARY_PATH中,因此我尝试使用我的函数将libdl.so和libgdiplus.so打包起来,但这也失败了,这次指出在libdgiplus.so中未找到入口点"GdiplusStartup"。这些文件不是来自Amazon Linux实例,因此我现在尝试安装Mono并从Amazon Linux实例获取它们。这没有帮助。
我尝试使用CoreCompat drawing library,但即使我尝试将其与函数捆绑在一起,它也会报告涉及libgdiplus.so的问题。
我之后在自己的Linux实例上尝试了一下,可以确认System.Drawing.Common有效。
有没有一些聪明的解决方案可以让我在AWS Lambda上使用System.Drawing.Common?还有其他方法可以欺骗我的lambda函数具有libdl并工作吗?
更新:
我们的最新尝试涉及使用AWS Lambda Layers,并小心地提取Docker Amazon Linux映像中apt安装的所有包,然后将其应用于它们自己的层。最终我们仍然遇到了“libdl”问题,所以我们放弃了。
人们建议的许多库的问题在于它们无法正确呈现日本文字,这对我们很重要。这似乎是一个不会在AWS Lambda上得到改善的问题,这没有帮助,最终更容易以Go重新编写我们的函数而不是继续使用C#。
由于下面的答案提到的库似乎适用于一般用途 - 可能现在支持日本文字 - 我选择接受我确信可以在AWS Lambda上工作的答案。

似乎是因为操作系统缺少libdl.so。请查看此链接:https://github.com/dotnet/corefx/issues/25102 - Gusman
@VAAA 我没有。我最近尝试使用ImageSharp,这是一个没有外部依赖的库,它似乎工作得很好,除非你需要绘制非ASCII文本。不幸的是,我需要 :-( - ProgrammingLlama
感谢@John。我希望System.Drawing.Common能够解决这个问题,或者AWS Lambda允许您上传DLL文件。谢谢。 - VAAA
2
使用PdfSharp / MigraDoc时遇到了同样的问题。这真的很糟糕。 - Frederik Nygaard Svendsen
3
使用ClosedXML时遇到了同样的问题。 - Roman Marusyk
显示剩余2条评论
4个回答

6

我在将我的应用程序上传到运行dotnet core 2.1.500版本的Ubuntu 18服务器后遇到了同样的问题。我使用https://github.com/dotnet/dotnet-docker/issues/618中MichaelSimons的建议解决了这个问题。

我运行了

#sudo apt-get update
#sudo apt-get install -y --allow-unauthenticated \
        libc6-dev \
        libgdiplus \
        libx11-dev \ 
#sudo rm -rf /var/lib/apt/lists/*

这解决了问题。


1
是的,这个方法解决了我的 Docker 镜像问题。不幸的是,我遇到问题的代码在 AWS Lambda 上运行 :( - ProgrammingLlama
你能否看一下我的问题,因为它与这个问题相似:https://dev59.com/57Pma4cB1Zd3GeqPr4fu。谢谢。 - w0051977
@John 为什么不尝试使用 CoreCompat.System.Drawing? - warrior
@din 我在我的问题中已经解决了这个问题。无论如何,我们的 Golang 版本的函数工作得足够好,不需要 C# 版本的。 - ProgrammingLlama
1
@John 我也遇到了同样的问题,但我使用了CoreCompat.System.Drawing和runtime.linux-x64.CoreCompat.System.Drawing解决了它。很高兴Go Lang对你有用。 - warrior

3
我找到了一个解决方案,对我很有效:
首先,我从项目中删除了System.Drawing.Common库,然后我安装了你可以在这里找到的库。它使用相同的类。
using System.Drawing
...
var bmp = new Bitmap(100,100);

最后,我安装了this另一个库,其中包含在Linux和Lambda上使用绘图库所需的所有dll。通过执行这些步骤,代码可以上传到AWS而不会出现任何问题。

1
你是在说v2 CoreCompat库现在可以用了吗?因为上次我尝试的时候不行。如果可以的话,我得再试一下。 - ProgrammingLlama
是的,我几个小时前尝试过了,只需包含Linux运行时即可。 - Alex HG

0
如果使用centOS,则可以使用以下命令:
  • sudo yum install libgdiplus

这对我的情况没有帮助。 - SerG

-1

在.NET Core Lambda中进行图像处理时,我使用SixLabors.ImageSharp

以下是我在最近的AWS re:Invent演讲中使用的代码,它执行了大量的图像处理:

var imageBuffer = new MemoryStream();

var resizeOptions = new ResizeOptions
{
    Size = new SixLabors.Primitives.Size { Width = this.TileSize, Height = this.TileSize},
    Mode = ResizeMode.Stretch
};
image.Mutate(x => x.Resize(resizeOptions));
image.Save(imageBuffer, new SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder());

imageBuffer.Position = 0;

+1 是因为它可能解决其他人的问题,但不幸的是,当我尝试使用日语文本时它没有起作用。 - ProgrammingLlama
6
如果你无法解决他们的问题,就不能只告诉他们尝试完全不同的范例。他问如何使System.Drawing.Common在AWS Lambda上工作 - 你甚至没有试图回答这个问题。 - R. McManaman
虽然这对我没有帮助,因为使用ImageSharp渲染日语文本存在问题(最终我不得不重新用Go而不是C#重写整个东西),但我相信这很可能是最好的通用选项。 - ProgrammingLlama

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接