Aws-lambda-dotnet: Apakah AWS Lambda mendukung pemanggilan System.Drawing dengan libgdiplus ?

Dibuat pada 18 Apr 2018  ·  7Komentar  ·  Sumber: aws/aws-lambda-dotnet

Hei,

Saya baru-baru ini mengimplementasikan pembuatan Captcha di AWS Lambda .NET Core 2 API saya. Saya berani bersumpah bahwa itu berjalan pada satu waktu, tetapi sekarang gagal. Saya telah melihat implementasi System.Drawing saat ini dari .NET Core; namun, dari apa yang saya baca, dependensi eksplisit pada GDI+ membuat pustaka ini tidak kompatibel lintas platform. Setelah diselidiki lebih lanjut, ada CompatCore.System.Drawing yang awalnya dikembangkan oleh tim Mono. Seharusnya, ini adalah versi Cross-platform dari System.Drawing yang mampu menggunakan implementasi GDI+ berbasis Linux; namun, mencoba menggunakannya hanya menimbulkan jejak kesalahan/tumpukan berikut:

System.TypeInitializationException: The type initializer for 'System.Drawing.GDIPlus' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'gdiplus': The specified module or one of its dependencies could not be found.
 (Exception from HRESULT: 0x8007007E)
   at System.Drawing.GDIPlus.GdiplusStartup(UInt64& token, GdiplusStartupInput& input, GdiplusStartupOutput& output)
   at System.Drawing.GDIPlus..cctor()
   --- End of inner exception stack trace ---
   at System.Drawing.GDIPlus.GdipCreateBitmapFromScan0(Int32 width, Int32 height, Int32 stride, PixelFormat format, IntPtr scan0, IntPtr& bmp)
   at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
   at Ivy.Captcha.Services.CaptchaGenerationService.GenerateCaptchaImage(Int32 captchaCharLength, Int32 width, Int32 height)
   at IAGE.Api.Data.Services.CaptchaApiService.GenerateCaptcha() in D:\Workspaces\iam-global-education\src\Api\IAGE.Api.Data\Services\CaptchaApiService.cs:line 63
   at lambda_method.lambda_method(Closure , Object , Object[] )
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Elmah.Io.AspNetCore.ElmahIoMiddleware.d__6.MoveNext()

Menurut utas berikut: https://github.com/CoreCompat/CoreCompat/issues/3

Saya seharusnya bisa memasukkan libgdiplus DLL ref dengan menambahkan paket runtime.linux-x64.CoreCompat.System.Drawing NuGet; Namun, itu tidak berhasil bagi saya. Saya telah mencoba berbagai kombinasi referensi perpustakaan dengan harapan ini akan menjadi masalah serupa yang telah dilihat banyak orang dengan System.Cryptography.x509Certificates; tapi saya belum menemukan kombinasi yang memungkinkan ini bekerja.

Adakah orang lain yang dapat mengaktifkan dan menjalankan fungsionalitas System.Drawing di AWS Lambda?

guidance

Komentar yang paling membantu

Ya Magick.NET telah diperbarui beberapa bulan yang lalu untuk bekerja lintas platform di luar kotak. Yang harus saya lakukan adalah menambahkannya ke proyek. Di bawah ini adalah fungsi Lambda yang saya tulis untuk membuat gambar mini dengannya.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
    <PackageReference Include="Amazon.Lambda.S3Events" Version="1.0.2" />
    <PackageReference Include="AWSSDK.S3" Version="3.3.16.2" />
    <PackageReference Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.1.0-beta" />
    <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="7.4.2" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="2.1.1" />
  </ItemGroup>

</Project>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Amazon.Lambda.S3Events;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.XRay.Recorder.Core;
using ImageMagick;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace ImageResizer
{
    public class Function
    {
        IAmazonS3 S3Client { get; set; }

        /// <summary>
        /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment
        /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the
        /// region the Lambda function is executed in.
        /// </summary>


        public Function()
        {
            Amazon.XRay.Recorder.Handlers.AwsSdk.AWSSDKHandler.RegisterXRayForAllServices();
            S3Client = new AmazonS3Client();
        }

        /// <summary>
        /// Constructs an instance with a preconfigured S3 client. This can be used for testing the outside of the Lambda environment.
        /// </summary>
        /// <param name="s3Client"></param>
        public Function(IAmazonS3 s3Client)
        {
            this.S3Client = s3Client;
        }

        HashSet<string> SupportedImageTypes { get; } = new HashSet<string> { ".png", ".jpg", ".jpeg" };

        /// <summary>
        /// This method is called for every Lambda invocation. This method takes in an S3 event object and can be used 
        /// to respond to S3 notifications.
        /// </summary>
        /// <param name="evnt"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task FunctionHandlerAsync(S3Event evnt, ILambdaContext context)
        {
            foreach (var record in evnt.Records)
            {
                var bucket = record.S3.Bucket.Name;
                var key = record.S3.Object.Key;

                if (key.StartsWith("thumbnails"))
                {
                    context.Logger.LogLine($"Object s3://{bucket}/{key} is already a thumbnail");
                    continue;
                }
                if (!SupportedImageTypes.Contains(Path.GetExtension(key.ToLower())))
                {
                    context.Logger.LogLine($"Object s3://{bucket}/{key} is not a supported image type");
                    continue;
                }

                context.Logger.LogLine($"Processing s3://{bucket}/{key}");

                MemoryStream resizedImageStream;
                using (var response = await this.S3Client.GetObjectAsync(bucket, key))
                {
                    AWSXRayRecorder.Instance.BeginSubsegment("Magick Image Resize");
                    try
                    {
                        using (MagickImageCollection collection = new MagickImageCollection(response.ResponseStream))
                        {
                            foreach (MagickImage image in collection)
                            {
                                image.Resize(200, 200);
                            }
                            context.Logger.LogLine($"   Image resized");

                            resizedImageStream = new MemoryStream();
                            collection.Write(resizedImageStream);
                            resizedImageStream.Position = 0;
                        }
                    }
                    catch(Exception e)
                    {
                        AWSXRayRecorder.Instance.AddException(e);
                        throw;
                    }
                    finally
                    {
                        AWSXRayRecorder.Instance.EndSubsegment();
                    }
                }

                var index = key.LastIndexOf('/');
                var thumbnailKey = "thumbnails/" + (index != -1 ? key.Substring(index + 1) : key);
                await this.S3Client.PutObjectAsync(new PutObjectRequest
                {
                    BucketName = bucket,
                    Key = thumbnailKey,
                    InputStream = resizedImageStream
                });

                context.Logger.LogLine($"   Thumbnail saved to s3://{bucket}/{thumbnailKey}");
            }
        }
    }
}

Semua 7 komentar

Saya telah mendengar tentang penggunaan libgdiplus untuk System.Drawing di Linux tetapi saya belum mencobanya. Untuk manipulasi gambar di Lambda saya telah menggunakan versi terbaru dari Magick.NET-Q16-AnyCPU . Saya belum pernah menggambar dengannya yang saya anggap Anda perlukan untuk Captcha tetapi saya melihatnya memang memiliki beberapa kemampuan menggambar .

Masalah saya tampaknya libgdiplus bukan instalasi default pada instance Lambda Linux. Seharusnya, runtime.linux-x64.CoreCompat.System.Drawing adalah paket NuGet yang hanya mengeksekusi skrip untuk menginstal pustaka ini melalui apt-get pada startup aplikasi; namun, setelah menggali kode untuk proyek ini melalui tautan di bawah ini, saya tidak dapat memahami dengan tepat cara kerjanya atau mengapa itu gagal bagi saya.

https://github.com/CoreCompat/CoreCompat/tree/master/native/runtime.linux-x64.CoreCompat.System.Drawing

Saya akan terus mencari solusi untuk saat ini; tetapi, tautan Magick.NET itu tampaknya merupakan metode yang valid untuk menghasilkan beberapa gambar Captcha, jadi saya pasti akan menyimpannya sebagai cadangan. Saya telah melihat ke dalam menggunakan System.Drawing asli karena tampaknya telah dikembangkan untuk kompatibilitas lintas platform yang lebih baik, tetapi tampaknya mereka dalam beberapa cara merujuk pustaka GDI+ yang diinstal,

Anda telah melihat paket Magick.NET ini berhasil digunakan di Lambda?

Ya Magick.NET telah diperbarui beberapa bulan yang lalu untuk bekerja lintas platform di luar kotak. Yang harus saya lakukan adalah menambahkannya ke proyek. Di bawah ini adalah fungsi Lambda yang saya tulis untuk membuat gambar mini dengannya.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
    <PackageReference Include="Amazon.Lambda.S3Events" Version="1.0.2" />
    <PackageReference Include="AWSSDK.S3" Version="3.3.16.2" />
    <PackageReference Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.1.0-beta" />
    <PackageReference Include="Magick.NET-Q16-AnyCPU" Version="7.4.2" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="2.1.1" />
  </ItemGroup>

</Project>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Amazon.Lambda.Core;
using Amazon.Lambda.S3Events;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.XRay.Recorder.Core;
using ImageMagick;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace ImageResizer
{
    public class Function
    {
        IAmazonS3 S3Client { get; set; }

        /// <summary>
        /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment
        /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the
        /// region the Lambda function is executed in.
        /// </summary>


        public Function()
        {
            Amazon.XRay.Recorder.Handlers.AwsSdk.AWSSDKHandler.RegisterXRayForAllServices();
            S3Client = new AmazonS3Client();
        }

        /// <summary>
        /// Constructs an instance with a preconfigured S3 client. This can be used for testing the outside of the Lambda environment.
        /// </summary>
        /// <param name="s3Client"></param>
        public Function(IAmazonS3 s3Client)
        {
            this.S3Client = s3Client;
        }

        HashSet<string> SupportedImageTypes { get; } = new HashSet<string> { ".png", ".jpg", ".jpeg" };

        /// <summary>
        /// This method is called for every Lambda invocation. This method takes in an S3 event object and can be used 
        /// to respond to S3 notifications.
        /// </summary>
        /// <param name="evnt"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task FunctionHandlerAsync(S3Event evnt, ILambdaContext context)
        {
            foreach (var record in evnt.Records)
            {
                var bucket = record.S3.Bucket.Name;
                var key = record.S3.Object.Key;

                if (key.StartsWith("thumbnails"))
                {
                    context.Logger.LogLine($"Object s3://{bucket}/{key} is already a thumbnail");
                    continue;
                }
                if (!SupportedImageTypes.Contains(Path.GetExtension(key.ToLower())))
                {
                    context.Logger.LogLine($"Object s3://{bucket}/{key} is not a supported image type");
                    continue;
                }

                context.Logger.LogLine($"Processing s3://{bucket}/{key}");

                MemoryStream resizedImageStream;
                using (var response = await this.S3Client.GetObjectAsync(bucket, key))
                {
                    AWSXRayRecorder.Instance.BeginSubsegment("Magick Image Resize");
                    try
                    {
                        using (MagickImageCollection collection = new MagickImageCollection(response.ResponseStream))
                        {
                            foreach (MagickImage image in collection)
                            {
                                image.Resize(200, 200);
                            }
                            context.Logger.LogLine($"   Image resized");

                            resizedImageStream = new MemoryStream();
                            collection.Write(resizedImageStream);
                            resizedImageStream.Position = 0;
                        }
                    }
                    catch(Exception e)
                    {
                        AWSXRayRecorder.Instance.AddException(e);
                        throw;
                    }
                    finally
                    {
                        AWSXRayRecorder.Instance.EndSubsegment();
                    }
                }

                var index = key.LastIndexOf('/');
                var thumbnailKey = "thumbnails/" + (index != -1 ? key.Substring(index + 1) : key);
                await this.S3Client.PutObjectAsync(new PutObjectRequest
                {
                    BucketName = bucket,
                    Key = thumbnailKey,
                    InputStream = resizedImageStream
                });

                context.Logger.LogLine($"   Thumbnail saved to s3://{bucket}/{thumbnailKey}");
            }
        }
    }
}

Saya baru saja masuk ke Magick dan saya pikir itu akan bekerja dengan baik. Anda tidak hanya memiliki akses ke API manipulasi gambar yang relatif beragam, tampaknya juga didukung lintas platform dengan baik. Terima kasih banyak atas sarannya, sedikit lebih banyak upaya pengembangan dan saya harus dapat menyelesaikan rintangan ini tanpa masalah!

Saya masih penasaran bagaimana beberapa orang tampaknya bisa menjalankan dan menjalankan implementasi GDI+. Saya tidak melihat cara apa pun untuk menginstal pustaka libgdiplus yang sesuai ke dalam Lambda sebelum eksekusi runtime.

Tampaknya ImageMagick Drawables API mungkin tidak kompatibel dengan Cross-Platform dengan AWS Lambda dari apa yang saya lihat. Setelah mengimplementasikan perpustakaan dan menjalankan fungsi Draw() , saya memunculkan kesalahan berikut:

ImageMagick.MagickDrawErrorException: NonconformingDrawingPrimitiveDefinition `text' @ error/draw.c/DrawImage/3402
   at ImageMagick.MagickExceptionHelper.Check(IntPtr exception)
   at ImageMagick.DrawingWand.NativeDrawingWand.Render()
   at ImageMagick.MagickImage.Draw(IEnumerable`1 drawables)
   at Ivy.Captcha.Magick.Services.MagickCaptchaGenerationService.GenerateCaptchaImage(Int32 captchaCharLength, Int32 width, Int32 height)
   at IAGE.Api.Data.Services.CaptchaApiService.GenerateCaptcha() in D:\Workspaces\iam-global-education\src\Api\IAGE.Api.Data\Services\CaptchaApiService.cs:line 63
   at lambda_method.lambda_method(Closure , Object , Object[] )
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Elmah.Io.AspNetCore.ElmahIoMiddleware.d__6.MoveNext()

Tidak peduli apa yang saya lakukan, sepertinya saya tidak bisa mendapatkan fungsi menggambar apa pun untuk bekerja di Lambda. Saya telah mencoba menggunakan System.Drawing (Microsoft), CoreCompat.System.Drawing (Mono), dan ImageMagick (Pihak ke-3), tetapi semuanya tampaknya tidak berhasil. Setiap perpustakaan pembuatan gambar tampaknya memiliki beberapa dependensi sistem utama yang sulit saya lakukan dengan AWS Lambda. Saya akan terus bereksperimen dan melaporkan kembali jika saya berhasil.

Apakah ada kemungkinan kami akan dapat menyesuaikan runtime Lambda kami di masa mendatang serupa dengan bagaimana kami dapat menyesuaikan wadah Docker? Semua ini dapat diselesaikan dengan eksekusi sederhana untuk menginstal libgdiplus ke instance Lambda saya.

Saya idiot dan seharusnya tidak pernah membuat gambar Captcha di server AWS Lambda saya ketika saya bisa menggunakan Google ReCaptcha. Dengan cara ini, AWS Lambda saya hanya menangani kode verifikasi dan tidak perlu mereferensikan segala bentuk fungsi menggambar.

Saya masih ingin melihat metode penerapan beberapa bentuk fungsi menggambar di AWS Lambda di masa mendatang; Namun, saya akan meletakkan masalah ini di belakang kompor dan kapur ini sampai keputusan desain yang mengerikan di pihak saya untuk saat ini.

Mungkin lapisan penyebaran Lambda dapat mengatasi masalah ini sampai dukungan yang tepat tersedia di .Net Core di beberapa titik.

https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html

Apakah halaman ini membantu?
0 / 5 - 0 peringkat