tuespetre / TuesPechkin

A .NET wrapper for the wkhtmltopdf library with an object-oriented API.
326 stars 116 forks source link

System.DllNotFoundException - Unable to load DLL 'wkhtmltox.dll': Access is denied #184

Open mertmtn opened 4 years ago

mertmtn commented 4 years ago

I am faced with the problem convert html to pdf using TuesPechkin. I have two applications on IIS and both of the apps have different application pool.

But I got an error from one of these:

Unable to load DLL 'wkhtmltox.dll': Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) Stack trace Server stack trace: at TuesPechkin.WkhtmltoxBindings.wkhtmltopdf_init(Int32 useGraphics) at TuesPechkin.PdfToolset.Load(IDeployment deployment) at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs) at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg) Exception rethrown at [0]: at TuesPechkin.ThreadSafeConverter.Invoke[TResult](FuncShim1 delegate) at Codaxy.WkHtmlToPdf.PdfConvert.ConvertHtmlToPdf(List1 documentlist) at ArastirmaYonetim.Controllers.RaporController.HtmlRaporOnizle(ArastirmaRaporAramaKriter raporAramaKriter)

But other app works correctly.

I checked that wkhtmltopdf file of both applications have right permission which is full control.

System web part of web config and I use .net framework 4.7.2

mertmtn commented 4 years ago

Also does it matter that Identity of application pool? I used application pool identity that set both of them.

tofer commented 3 years ago

Did you ever figure this out @mertmtn? I am having the same issue

mertmtn commented 3 years ago

@tofer When I tried to change application pool identity on IIS, it works. I do not remember that what I selected identity. It can be related to your server. You must try to change identity

tofer commented 3 years ago

Thanks @mertmtn for the reply.

I actually found the reason for the issue (as I was having it), which is this line in the TempFolderDeployment class.

It uses the application's base directory name AppDomain.CurrentDomain.BaseDirectory.GetHashCode().ToString() to build the name of the temporary folder it uses to place the DLL. In my application, I have development/production versions of the same application on the same server, which ultimately use the same directory name, so they were conflicting.

I re-wrote the IDeployment implementation myself to use the IIS site name instead, and voila, problem solved. Not robustly tested, but works for me for anyone interested:

    [Serializable]
    public class IISTempFolderDeployment : IDeployment
    {
        public string Path { get; }

        public CustomTempFolderDeployment()
        {
            // Build a folder name to use in the system's temp directory based on the IIS site name (sanitized)
            var appFolder = System.IO.Path.GetInvalidFileNameChars() 
                .Aggregate($"wkhtmltox-{System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName()}",
                    (current, c) => current.Replace(c, '-'));

            Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), appFolder);
        }
    }

with usage

Converter = new ThreadSafeConverter(new RemotingToolset<PdfToolset>(new WinAnyCPUEmbeddedDeployment(new IISTempFolderDeployment())));

Now instead prod/dev using C:\Windows\Temp\745135165\8\0.12.4.1 The DLL is extracted to C:\Windows\Temp\wkhtmltox-mysitename-prod\0.12.4.1 and C:\Windows\Temp\wkhtmltox-mysitename-dev\0.12.4.1

mertmtn commented 3 years ago

@tofer Is IISTempFolderDeployment class your custom one? Which layer uses the class on your project.

Maybe I used on my project, if i need. It stay as another solution.

tofer commented 3 years ago

@mertmtn yes the IISTempFolderDeployment class is what I wrote for my applications. I used it as a drop-in replacement of the TempFolderDeployment class.