pruiz / WkHtmlToXSharp

C# wrapper wrapper (using P/Invoke) for the excelent Html to PDF conversion library wkhtmltopdf library.
239 stars 84 forks source link

Poor performance from ASP.NET MVC application #8

Closed tjaskula closed 8 years ago

tjaskula commented 12 years ago

Hi,

I encounter a poor perfomrance issue (1 minute for PDF generation of simple html page, no concurrent requests) while using WkHTMLToXSharp from whitin a ASP.NET MVC 3 application and .NET framework 4.0. I'm using a MultiplexingConverter like in the example below :

var wk = new MultiplexingConverter(); wk.GlobalSettings.Margin.Top = "0cm"; wk.GlobalSettings.Margin.Bottom = "0cm"; wk.GlobalSettings.Margin.Left = "0cm"; wk.GlobalSettings.Margin.Right = "0cm";

wk.ObjectSettings.Web.EnablePlugins = false; wk.ObjectSettings.Web.EnableJavascript = false; wk.ObjectSettings.Page = url;

wk.ObjectSettings.Load.Proxy = "none";

Do you have any hints, what's going on or how can I debug/improve it ?

Thanks,

pruiz commented 12 years ago

Hi,

Calling the convertir for the first time forces a few initialization tasks on the background, one minute sounds too much, but never mind.

Do you simple perform one conversion or have you tried performing a few conversions in a row and take the average?

Sent from my iPad

On 06/08/2012, at 15:55, Jaskula reply@reply.github.com wrote:

Hi,

I encounter a poor perfomrance issue (1 minute for PDF generation of simple html page, no concurrent requests) while using WkHTMLToXSharp from whitin a ASP.NET MVC 3 application and .NET framework 4.0. I'm using a MultiplexingConverter like in the example below :

var wk = new MultiplexingConverter(); wk.GlobalSettings.Margin.Top = "0cm"; wk.GlobalSettings.Margin.Bottom = "0cm"; wk.GlobalSettings.Margin.Left = "0cm"; wk.GlobalSettings.Margin.Right = "0cm";

wk.ObjectSettings.Web.EnablePlugins = false; wk.ObjectSettings.Web.EnableJavascript = false; wk.ObjectSettings.Page = url;

wk.ObjectSettings.Load.Proxy = "none";

Do you have any hints, what's going on or how can I debug/improve it ?

Thanks,


Reply to this email directly or view it on GitHub: https://github.com/pruiz/WkHtmlToXSharp/issues/8

tjaskula commented 12 years ago

Hi Pablo,

I noticed few things that maybe play a crucial part here. First of all I noticed that for each request a new instance of MultiplexingConverter is created. It takes time to initialize and only the first export works. Everytime on the next export I receive the followinf errors :

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at WkHtmlToXSharp.WkHtmlToPdfConverter.wkhtmltopdf_convert(IntPtr converter) at WkHtmlToXSharp.WkHtmlToPdfConverter._Convert(String inputHtml) in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\WkHtmlToPdfConverter.cs:line 392 at WkHtmlToXSharp.WkHtmlToPdfConverter.Convert() in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\WkHtmlToPdfConverter.cs:line 436 at WkHtmlToXSharp.MultiplexingConverter.b__8() in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\MultiplexingConverter.cs:line 87 --- End of inner exception stack trace --- at Sanford.Threading.DelegateQueue.EndInvoke(IAsyncResult result) in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\DelegateQueue\DelegateQueue.cs:line 492 at Sanford.Threading.DelegateQueue.Invoke(Delegate method, Object[] args) in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\DelegateQueue\DelegateQueue.cs:line 546 at WkHtmlToXSharp.MultiplexingConverter.Convert() in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\MultiplexingConverter.cs:line 87

which finishes with error 500.

Do you think I should define the MultiplexingConverter as a singleton service ?

Thanks in advance.

Thomas

pruiz commented 12 years ago

Looks a bit wierd, Can you povide a simple test case ir programa with you error?

Sent from my iPad

On 06/08/2012, at 16:32, Jaskula reply@reply.github.com wrote:

Hi Pablo,

I noticed few things that maybe play a crucial part here. First of all I noticed that for each request a new instance of MultiplexingConverter is created. It takes time to initialize and only the first export works. Everytime on the next export I receive the followinf errors :

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at WkHtmlToXSharp.WkHtmlToPdfConverter.wkhtmltopdf_convert(IntPtr converter) at WkHtmlToXSharp.WkHtmlToPdfConverter._Convert(String inputHtml) in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\WkHtmlToPdfConverter.cs:line 392 at WkHtmlToXSharp.WkHtmlToPdfConverter.Convert() in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\WkHtmlToPdfConverter.cs:line 436 at WkHtmlToXSharp.MultiplexingConverter.b__8() in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\MultiplexingConverter.cs:line 87 --- End of inner exception stack trace --- at Sanford.Threading.DelegateQueue.EndInvoke(IAsyncResult result) in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\DelegateQueue\DelegateQueue.cs:line 492 at Sanford.Threading.DelegateQueue.Invoke(Delegate method, Object[] args) in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\DelegateQueue\DelegateQueue.cs:line 546 at WkHtmlToXSharp.MultiplexingConverter.Convert() in C:\Users\tjaskula\Documents\GitHub\WkHtmlToXSharp\WkHtmlToXSharp\MultiplexingConverter.cs:line 87

which finishes with error 500.

Do you think I should define the MultiplexingConverter as a singleton service ?

Thanks in advance.

Thomas


Reply to this email directly or view it on GitHub: https://github.com/pruiz/WkHtmlToXSharp/issues/8#issuecomment-7525251

tjaskula commented 12 years ago

Pablo,

It's rather strightforward. The code I showed you before is executed in the MVC action like that :

            var wk = new MultiplexingConverter();
            wk.GlobalSettings.Margin.Top = "0cm";
            wk.GlobalSettings.Margin.Bottom = "0cm";
            wk.GlobalSettings.Margin.Left = "0cm";
            wk.GlobalSettings.Margin.Right = "0cm";

            wk.ObjectSettings.Web.EnablePlugins = false;
            wk.ObjectSettings.Web.EnableJavascript = false;
            wk.ObjectSettings.Page = url;

            wk.ObjectSettings.Load.Proxy = "none";

            return File(wk.Convert(), "application/pdf", "test.pdf");

The error I mentioned before I have from time to time. I can't reproduce it right now but the performances are poor anyway. If I reproduce the error I'll post it to you with more details.

Do you have any hints how improve the performances ? Maybe I should move the initialisation to the application start code ?

pruiz commented 12 years ago

I was expecting you were executing it under IIS.

Please read the README file available with the source code, as you'll find, running this library under IIS is not supported.

Pablo

On Tue, Aug 7, 2012 at 11:31 AM, Jaskula notifications@github.com wrote:

Pablo,

It's rather strightforward. The code I showed you before is executed in the MVC action like that :

        var wk = new MultiplexingConverter();
        wk.GlobalSettings.Margin.Top = "0cm";
        wk.GlobalSettings.Margin.Bottom = "0cm";
        wk.GlobalSettings.Margin.Left = "0cm";
        wk.GlobalSettings.Margin.Right = "0cm";

        wk.ObjectSettings.Web.EnablePlugins = false;
        wk.ObjectSettings.Web.

EnableJavascript = false; wk.ObjectSettings.Page = url;

        wk.ObjectSettings.Load.Proxy = "none";

        return File(wk.Convert(), "application/pdf", "test.pdf");

The error I mentioned before I have from time to time. I can't reproduce it right now but the performances are poor anyway. If I reproduce the error I'll post it to you with more details.

Do you have any hints how improve the performances ? Maybe I should move the initialisation to the application start code ?

— Reply to this email directly or view it on GitHubhttps://github.com/pruiz/WkHtmlToXSharp/issues/8#issuecomment-7547992.

tjaskula commented 12 years ago

Pablo,

Before I go further with tests, will that work if I host the exporting code in another 32 bit application pool on IIS. From what I can read if I compile it with x86 setting and make it run on IIS 32 bit, then it should work.

Thanks

pruiz commented 12 years ago

The problem with IIS is that it recycles app. pools from time to time, but during this process any non-managed resources hold by your application may (as in this case) end up not being appropiatelly freed.

Also, having more than one AppDomain under you'r IIS application can cause memory corruption, as both AppDomains try to instantiante a WebKit instance under the same process (ie. same process memory/space), and that's another no-way.

The best thing you can do is having a Daemon or Service handling HTML2PDF conversión, and calling it from your web app. using remoting, WS calls, or any other RPC method. This will also help you de-compose your application and making things easier to debug.

Hope it helps.

On Tue, Aug 7, 2012 at 1:01 PM, Jaskula notifications@github.com wrote:

Pablo,

Before I go further with tests, will that work if I host the exporting code in another 32 bit application pool on IIS. From what I can read if I compile it with x86 setting and make it run on IIS 32 bit, then it should work.

Thanks

— Reply to this email directly or view it on GitHubhttps://github.com/pruiz/WkHtmlToXSharp/issues/8#issuecomment-7549845.

tjaskula commented 12 years ago

Thank you Pablo for more details. I'll try to sum up. So the main problem is that because of app pools recycling there is no way to clearly free up unmanaged ressources.

As for AppDomains, I was suggesting to run WebKit instance only on one application pool and the other one should only run application code.

I'll try to split it to another service.

Thanks,

tjaskula commented 12 years ago

Pablo, I moved the code that uses WkHtmlToXSharp to the web service that is hosted in the Console application. The service is compiled against x86 (normal for console apps). I tired different approaches (MultiplexingConverter as singleton or initializd on each call to the webservice).

I don't encounter any problems except that performances are really poor. More than one minute for a simple page conversion to pdf. The page responds in ms in the browser. I'm testing with one request at a time.

What might be the problem ?

Thanks in advance for your help.

pruiz commented 12 years ago

Can you run in your enviroment the unit tests accompanying the source code, to test performance?

Also, are you providing a static html file located withing your local filesystem, or a remote URL?

Pablo

On Tue, Aug 7, 2012 at 6:04 PM, Jaskula notifications@github.com wrote:

Pablo, I moved the code that uses WkHtmlToXSharp to the web service that is hosted in the Console application. The service is compiled against x86 (normal for console apps). I tired different approaches (MultiplexingConverter as singleton or initializd on each call to the webservice).

I don't encounter any problems except that performances are really poor. More than one minute for a simple page conversion to pdf. The page responds in ms in the browser. I'm testing with one request at a time.

What might be the problem ?

Thanks in advance for your help.

— Reply to this email directly or view it on GitHubhttps://github.com/pruiz/WkHtmlToXSharp/issues/8#issuecomment-7558082.

tjaskula commented 12 years ago

Actually I can't run the tests. I have the following exception :

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.DllNotFoundException: Unable to load DLL 'wkhtmltox0': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Thomas

pruiz commented 12 years ago

wkhtmltox0.dll is stored along the source code and it get's embedded into the generated WkHtmlToXSharp.dll so it can be automatically deployed on first time execution.. And given the fact that you did not experience such problem on your other tests, I guess this autodemployment works already on your enviroment.

So it would be helpful to know a bit more on how are you running the unit tests, please try to elaborate a bit more so I can try to help you.

On Thu, Aug 9, 2012 at 12:22 PM, Jaskula notifications@github.com wrote:

Actually I can't run the tests. I have the following exception :

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.DllNotFoundException: Unable to load DLL 'wkhtmltox0': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Thomas

— Reply to this email directly or view it on GitHubhttps://github.com/pruiz/WkHtmlToXSharp/issues/8#issuecomment-7610496.

tjaskula commented 12 years ago

Pablo,

I tried to compile and to run the tests but it didn't work. I had to copy wkhtmltox0.dll to the test bin folder in order to make work the unit tests. So when I used the dll from the Win32 folder I got another exception 'BadImageFormat" or something like that. Then I copied wkhtmltox0.dll from Win64 folder. It works but the first tests "CanConvertConcurrently" fails :

2012/08/09 12:29:39:728 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:739 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:740 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:742 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:744 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData Delegate Queue Thread: 1 Started. 2012/08/09 12:29:42:672 [INFO] WkHtmlToXSharp.MultiplexingConverter - Initializing converter infrastructure.. 2012/08/09 12:29:44:379 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:380 [INFO] WkHtmlToXSharp.MultiplexingConverter - Initialized converter infrastructure.. 2012/08/09 12:29:44:382 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:383 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:384 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:384 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:385 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:389 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:647 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Conversion begin, phase count: 7 2012/08/09 12:29:46:701 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - PhaseChanged: 1 - Loading pages 2012/08/09 12:29:46:703 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 0 - 0% 2012/08/09 12:29:46:743 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 10 - 10% 2012/08/09 12:29:47:506 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 33 - 33%

Test exceeded Timeout value of 50000ms Exception doesn't have a stacktrace

The second one "CanConvertFromFile" is still running since 5 minutes.

I guess I made something wrong.

Thomas

pruiz commented 12 years ago

You need to set your build to 32bit, and use 32bit version of wkhtmltox0.dll.. If you get 'BadImageFormat' is because you are running your .net app under 64bit, but using the 32bit native dll version, or the opposite.

Also, if autodeployment didnt work, it might be due to permissions on folders, etc. However, you can manually copy the file as you did.

On Thu, Aug 9, 2012 at 12:41 PM, Jaskula notifications@github.com wrote:

Pablo,

I tried to compile and to run the tests but if didn't work. I had to copy wkhtmltox0.dll to the test bin folder in order to make work the unit tests. So when I used the dll from the Win32 folder I got another exception 'BadImageFormat" or something like that. Then I copied wkhtmltox0.dll from Win64 folder. It works but the first tests "CanConvertConcurrently" fails :

2012/08/09 12:29:39:728 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:739 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:740 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:742 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData 2012/08/09 12:29:39:744 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - New thread WkHtmlToXSharp.Tests.PdfConverterTest+ThreadData Delegate Queue Thread: 1 Started. 2012/08/09 12:29:42:672 [INFO] WkHtmlToXSharp.MultiplexingConverter - Initializing converter infrastructure.. 2012/08/09 12:29:44:379 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:380 [INFO] WkHtmlToXSharp.MultiplexingConverter - Initialized converter infrastructure.. 2012/08/09 12:29:44:382 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:383 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:384 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:384 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:385 [DEBUG] WkHtmlToXSharp.WkHtmlToPdfConverter - Initialized new converter instance (Version: 0.10.0_rc1, UseX11 = False) 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:389 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:387 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Performing conversion.. 2012/08/09 12:29:44:647 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Conversion begin, phase count: 7 2012/08/09 12:29:46:701 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - PhaseChanged: 1 - Loading pages 2012/08/09 12:29:46:703 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 0 - 0% 2012/08/09 12:29:46:743 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 10 - 10% 2012/08/09 12:29:47:506 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 33 - 33%

Test exceeded Timeout value of 50000ms Exception doesn't have a stacktrace

The second one "CanConvertFromFile" is still running since 5 minutes.

I guess I made something wrong.

Thomas

— Reply to this email directly or view it on GitHubhttps://github.com/pruiz/WkHtmlToXSharp/issues/8#issuecomment-7610835.

tjaskula commented 12 years ago

I compiled to x86 and took a library from Win32 folder. The unit test run is as before. Timeout on the first one and stuck on the second one without going further.

tjaskula commented 12 years ago

Well I tried to figure out what's going on but it always blocks on :

2012/08/10 10:42:10:717 [DEBUG] WkHtmlToXSharp.Tests.PdfConverterTest - Conversion begin, phase count: 7 2012/08/10 10:42:10:732 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - PhaseChanged: 1 - Loading pages 2012/08/10 10:42:10:733 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 0 - 0% 2012/08/10 10:42:10:733 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 10 - 10% 2012/08/10 10:42:10:760 [INFO] WkHtmlToXSharp.Tests.PdfConverterTest - ProgressChanged: 33 - 33%

It seems that it's looping on result.AsyncWaitHandle.WaitOne(); in DelegateQueue.

Thomas

rbkaranam commented 9 years ago

Hello ..

I arrived in here as I too started getting these exceptions when running the HTML to PDF conversion under IIS 6.0.

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Do you have a fix for this issue or any work around ? Should I place this conversion logic outside of IIS. Please advise.

dobragab commented 9 years ago

Hello,

I've got the same issue as rbkaranam. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

VS 2013 and c# Windows Forms Application.

Also this issue:

https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1542

using Bookman Old Style...

Any help would be appreciated.

Thanks.

pruiz commented 8 years ago

Running this library under ASP.NET (or more specifically IIS) is not supported. This has to do with the way IIS manages underlaying threads, and application pools.

What most people do (myself included) is to create a daemon or windows service which handles requests from the ASP.NET/MVC/etc. process via any form of RPC or queuing.

Regards