mono / SkiaSharp

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images.
MIT License
4.43k stars 537 forks source link

ArgumentException: "Cannot pass a GCHandle across AppDomains" while running ASP.NET MVC application in the IIS Server. #2721

Open LokeshBaskar opened 8 months ago

LokeshBaskar commented 8 months ago

Description

We are using the SkiaSharp library to generate an image using SKData in an ASP.NET MVC application. When running the MVC application as multiple sites(Use same folder for all the sites) in the local IIS Server under one application pool (using the same pool name for all the site), we encounter an ArgumentException while browsing in IIS.

Note: Initially build the MVC application locally in Visual studio, then run in local IIS server. This exception "Cannot pass a GCHandle across AppDomains" occurs randomly while browsing it in the IIS server.

Reproduction sample Link Download the MVCSample.zip to replicate the problem.

Reference link for how to setup or install IIS server locally. https://learn.microsoft.com/en-us/aspnet/web-forms/overview/deployment/visual-studio-web-deployment/deploying-to-iis#install-iis

Reference link for how to add the ASP .NET MVC application as website on the IIS server by using the UI. Then create more sites like this with single MVC application. https://learn.microsoft.com/en-us/iis/application-frameworks/scenario-build-an-aspnet-website-on-iis/configuring-step-1-install-iis-and-asp-net-modules#to-add-an-aspnet-application-by-using-the-ui

Code

public ActionResult CreateImage()
{
    //Open the file as Stream
    FileStream imageData = new FileStream(Server.MapPath("~/App_Data/AdventureCycle.png"), FileMode.Open, FileAccess.Read);
    MemoryStream outputStream = new MemoryStream();
    using (SKData skImgData = SKData.Create(imageData))
    {
        skImgData.SaveTo(outputStream);
    }
    outputStream.Position = 0;
    imageData.Close();
    //Download Image file in the browser.
    return File(outputStream, "image/png", "Output_Image.png");
}

Expected Behavior

SkiaSharp should create images properly without any errors when running an MVC application in multiple sites under one application pool in local IIS.

Actual Behavior

The following error we were faced randomly in the IIS server. Exception Details: System.ArgumentException: Cannot pass a GCHandle across AppDomains.

Stack Trace:
[ArgumentException: Cannot pass a GCHandle across AppDomains.
Parameter name: handle]
   SkiaSharp.SKAbstractManagedStream.DisposeNative() in D:\a\1\s\binding\Binding\SKAbstractManagedStream.cs:52
   SkiaSharp.SKNativeObject.Dispose(Boolean disposing) in D:\a\1\s\binding\Binding\SKObject.cs:287
   SkiaSharp.SKManagedStream.Dispose(Boolean disposing) in D:\a\1\s\binding\Binding\SKManagedStream.cs:53
   SkiaSharp.SKNativeObject.Dispose() in D:\a\1\s\binding\Binding\SKObject.cs:298
   SkiaSharp.SKData.Create(Stream stream, Int64 length) in D:\a\1\s\binding\Binding\SKData.cs:141
   MVCSample.Controllers.HomeController.CreateImage() in D:\SkiaSharpSample\MVCSample\MVCSample\Controllers\HomeController.cs:30

Version of SkiaSharp

2.88.3 (Current)

Last Known Good Version of SkiaSharp

2.88.2 (Previous)

IDE / Editor

Visual Studio (Windows)

Platform / Operating System

Windows

Platform / Operating System Version

No response

Devices

Basic Information:SkiaSharp Version with issue: 2.88.7 • IDE: Visual Studio Professional 2022 Preview 17.9.0 Preview 1.0 • Platform: Windows (Windows 11 Enterprise) version: 23H2 • Target Frameworks: ASP .NET MVC Application of .NET Framework 4.8

Relevant Screenshots

image

Relevant Log Output

[ArgumentException: Cannot pass a GCHandle across AppDomains.
Parameter name: handle]
   SkiaSharp.SKAbstractManagedStream.DisposeNative() in D:\a\1\s\binding\Binding\SKAbstractManagedStream.cs:52
   SkiaSharp.SKNativeObject.Dispose(Boolean disposing) in D:\a\1\s\binding\Binding\SKObject.cs:287
   SkiaSharp.SKManagedStream.Dispose(Boolean disposing) in D:\a\1\s\binding\Binding\SKManagedStream.cs:53
   SkiaSharp.SKNativeObject.Dispose() in D:\a\1\s\binding\Binding\SKObject.cs:298
   SkiaSharp.SKData.Create(Stream stream, Int64 length) in D:\a\1\s\binding\Binding\SKData.cs:141
   MVCSample.Controllers.HomeController.CreateImage() in D:\SkiaSharpSample\MVCSample\MVCSample\Controllers\HomeController.cs:30

Code of Conduct

AkashArul26 commented 8 months ago

Hi team,

Any update in this?

Regards, Akash.

MohanaselvamJ commented 7 months ago

I am also facing same problem. Any workaround or solution would be helpful.

LokeshBaskar commented 7 months ago

Hi Team, Any update on this issue? Any workaround or solution would be helpful, as we have been waiting for a while.

mdy14226 commented 6 months ago

having similar issue and it crashed IIS every time.

LokeshBaskar commented 5 months ago

Hi Team, Any update on this issue? Any workaround or solution would be helpful, as we have been waiting for a while.

mattleibow commented 5 months ago

I am not too familiar with the way IIS works, but SkiaSharp is using GCHandles to get direct access to memory for drawing and processing pixels. Is there a way to mark a controller as not usable across app domains? Maybe the image logic needs to be in a separate place that can be marked or controlled as such?

I did a quick search and this came up: https://github.com/cefsharp/CefSharp/issues/351

If anyone has more info on IIS and how this would work, please let me know.