dlemstra / Magick.NET

The .NET library for ImageMagick
Apache License 2.0
3.42k stars 413 forks source link

Magick.Native-Q8-x64.dll Access Denied (File Locked) #1537

Open pdhenrique3 opened 7 months ago

pdhenrique3 commented 7 months ago

Magick.NET version

8.2.1

Environment (Operating system, version and so on)

Windows Server 2016, .NET Framework 4.7.1

Description

I have two WebAPI Applications on the same Server, different IIS Application Pools, Magick-Q8 8.2.1 AnyCPU. Both of them applies Magick on images contained in the Temp File Path of the Server.

Inside this Path, Magick generates a folder, containing this file Magick.Native-Q8-x64.dll which is used.

image image

When the first application starts, success, but the file Magick.Native-Q8-x64.dll get locked by the application, and the second application's requests gets the error:

The type initializer for 'NativeMagickSettings' threw an exception. ---> System.TypeInitializationException: The type initializer for 'X64' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'Magick.Native-Q8-x64.dll': Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

I had to unify both applications under the same Application Pool to make them work, but even if there are no code errors locking the file for any longer than necessary, it happens in some time, and this error could still happen in a much smaller possibility

Steps to Reproduce

In a Microsoft IIS, Two applications using Magick.NET.Core 8.2.1 and Magick.NET-Q8-AnyCPU 8.2.1, each one in your own AppPool

Open a file in the Server's Tem FilePath, perform image resize and compress, save the file

Do this in both applications

dlemstra commented 7 months ago

I would advise you to upgrade to the most recent version. I cannot help you with an older release than the most recent one.

You can use MagickNET.SetNativeLibraryDirectory to control the location of the folder those files are written. You might be lucky and have that available in your version but I would still advise you to upgrade due to security issues.

shanji97 commented 3 months ago

Something simmilar is happening on 13.7.0. (upgraded from 13.1.3 when building the daily version of our app. It seems it happens randomly. Here is the log from the Jenkins build process. image image The only fix for now seems to be recycling the application pool on IIS.

dlemstra commented 3 months ago

Your app pool is locking those files. There is not much I can do about that.

shanji97 commented 3 months ago

🤔 Ok, so I checked the code and put the magick image objects into a using statement. Currently there are no issues related to the locking of the files.

dlemstra commented 3 months ago

Thanks for coming back and mentioning this tip for future readers. This is probably going to help someone in the future!

shanji97 commented 2 months ago

So we encountered a bug where presumably IIS is locking the Image Magick DLLs.

URL: our custom
Type: GET
Source: Magick.NET-Q8-AnyCPU
Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'MagickSettings_SetFont' in DLL 'Magick.Native-Q8-x64.dll'.
   at ImageMagick.MagickSettings.NativeMethods.X64.MagickSettings_SetFont(IntPtr Instance, IntPtr value)
   at ImageMagick.MagickSettings.NativeMagickSettings.SetFont(String value)
   at ImageMagick.MagickSettings.CreateNativeInstance(IMagickSettings`1 instance)
   at ImageMagick.MagickImage.NativeMagickImage..ctor(IMagickSettings`1 settings)
   at ImageMagick.MagickImage..ctor()
   at ImageMagick.MagickImage..ctor(Stream stream)
   at Pages_Vlozisce_Attachment.GeneralScaleImage(Byte[] attachmentData, Int32 rotation, Int32 page)
   at Pages_Vlozisce_Attachment.ScaleImage(Byte[] attachmentData, Int32 rotation, Int32 page, MimeType mimeType)
   at Pages_Vlozisce_Attachment.Page_Load(Object sender, EventArgs e)
   at System.Web.UI.Control.OnLoad(EventArgs e)
   at Marg.BusinessConnect.Gui.BasePage.OnLoad(EventArgs e)
   at System.Web.UI.Control.LoadRecursive()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

I checked the DLL with Dependency Walker x64 and every DLL I scanned contained the aforementioned entry point. Since I had another IM related feature request (the support of HEIC and HEIF files - so we had to move to Q16-HDRI), I noticed, that I had trouble to remove the Magick.Native-Q8-x64.dll with the command nant.cmd clean. What worked was to recycle the IIS Application Pool and then the deletion worked perfectly. I the manually changed the DLL on our test server (of course I recycled the Application Pool first) and then the upgrade/replacement of the DLL worked smoothly and no errors are being thrown. Is there any way to track these kinds of DLL locks on a low level?

wsion commented 1 month ago

@pdhenrique3 I am using Magick.Net 7.17.0.0 in my application, and met exactly the same issue some days ago. Not sure how the other version does, by reading the source code of the version I'm using, I see SetNativeLibraryDirectory() not really set the directory for extracting and placing the native libary. In fact, the folder in windows temp folder for placing the native libary named CacheDirectory. Finally I resolved the issue by manually setting the CacheDirectory to other place during starting my application. Below code might help someone who met similar issue. I just put the code snippet in my Application_Start() method of Global.asax.cs..

image

shanji97 commented 3 days ago

@pdhenrique3 I am using Magick.Net 7.17.0.0 in my application, and met exactly the same issue some days ago. Not sure how the other version does, by reading the source code of the version I'm using, I see SetNativeLibraryDirectory() not really set the directory for extracting and placing the native libary. In fact, the folder in windows temp folder for placing the native libary named CacheDirectory. Finally I resolved the issue by manually setting the CacheDirectory to other place during starting my application. Below code might help someone who met similar issue. I just put the code snippet in my Application_Start() method of Global.asax.cs..

image

Is this somehow applicable when using nuget packages Magick.NET.Core and AnyCPU.Q16-HDRI? The version is 13.9.1. The error I am getting is MagickAnyCPU does not exist in the namespace ImageMagick. (CS0234 error)

dlemstra commented 3 days ago

The SetNativeLibraryDirectory method has moved to the MagickNET class.