Welcome Guest Search | Active Topics | Sign In | Register

Thread Safety of EO.Pdf.HtmlToPdf Options
Jeremy
Posted: Tuesday, November 29, 2011 11:21:24 AM
Rank: Newbie
Groups: Member

Joined: 11/29/2011
Posts: 4
I am testing implementing the EO.Pdf.HtmlToPdf in a webapplication.

However it appears that it's not threadsafe. I was weary when I saw the only way to access it was through a static method, so I set out to test it. I throw 6 threads at a time at it and rather consistently it throws an exception.

I am seeing both:

[System.IO.EndOfStreamException]{"Unable to read beyond the end of the stream."}

it occurs at:
at System.IO.__Error.EndOfFile()
at System.IO.MemoryStream.InternalReadInt32()
at System.IO.BinaryReader.ReadInt32()
at EO.Pdf.Internal.bb.a(Byte[] A_0, Single A_1, Single A_2, Single A_3, Single A_4, Double A_5, Double A_6)
at EO.Pdf.Internal.km.a(String A_0, Boolean A_1, String A_2)
at EO.Pdf.Internal.km.a()

as well as:

[System.ArgumentNullException]{"Buffer cannot be null.\r\nParameter name: buffer"}

it occurs at:
at System.IO.MemoryStream..ctor(Byte[] buffer, Boolean writable)
at System.IO.MemoryStream..ctor(Byte[] buffer)
at EO.Pdf.Internal.bb.a(Byte[] A_0, Single A_1, Single A_2, Single A_3, Single A_4, Double A_5, Double A_6)
at EO.Pdf.Internal.km.a(String A_0, Boolean A_1, String A_2)
at EO.Pdf.Internal.km.a()


I'm certainly not an expert on this stuff, but I am sure that I'm passing a unique instance of the MemoryStream to the the converter and the second error looks like a constructor call that's outside my control anyway.

Has anyone else run into this, or is there are way to use the EO.Pdf.HtmlToPdf other than the static methods?
eo_support
Posted: Tuesday, November 29, 2011 12:22:58 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

EO.Pdf is designed to be multithread safe on static members. If you call instance methods across multithread, then you need to synchronize in your code. If you see anything that does not work this way, try to create a test project and we will be happy to take a look.

Thanks
Jeremy
Posted: Tuesday, November 29, 2011 12:46:53 PM
Rank: Newbie
Groups: Member

Joined: 11/29/2011
Posts: 4
Ok. I will try to do this later. I've been doing more testing, It is clearly having issues with threadsafety. It only seems to trigger if the requests are <100ms apart. It is prior to the internal flow control because setting the Options to limit max requests doesn't affect the error. This afternoon I'll strip my specific code from my unit test and post the example.
Jeremy
Posted: Tuesday, November 29, 2011 2:08:41 PM
Rank: Newbie
Groups: Member

Joined: 11/29/2011
Posts: 4
Here is an example of what I was running. You can cut and paste this into a project that has EO.PDF and nUnit to see what I am talking about. If you don't have nUnit in the project you can simply remove the assertions and inline the testdelegate and you still see the behavior I am talking about.


Code: C#
[Test]
        public void testConcurrency()
        {
            //Arrange
            bool errorOccured = false;
            object errorLock = new object();
            string html = "&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;This Is Html!&lt;/body&gt;&lt;/html&gt;";
            

            Action testCall = () =>
            {
                try {
                    string htmlcopy = html.Substring(0);
                    MemoryStream stream = new MemoryStream();
                    EO.Pdf.HtmlToPdf.ConvertHtml(htmlcopy, stream);
                }
                catch (Exception e)
                {
                    lock (errorLock) { errorOccured = true; }
                    throw e;
                }
            };

            List<WaitHandle> handles = new List<WaitHandle>();

            //Act
            TestDelegate del = () =>
                {
                    for (int j = 0; j < 50; j++)
                    {
                        for (int i = 0; i < 6; i++)
                        {
                            handles.Add(testCall.BeginInvoke(null, null).AsyncWaitHandle);
                            
                        }
                        WaitHandle.WaitAll(handles.ToArray());
                        handles.Clear();
                    }                    
                };

            //Assert
            Assert.DoesNotThrow(del);
            Assert.IsFalse(errorOccured);
        }


eo_support
Posted: Wednesday, November 30, 2011 12:21:59 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

Thanks for the code. We were able to reproduce fix the problem. We are still doing some more testing and as soon as that is done, we should be able to provide you the new build. It should come either today or tomorrow.

Thanks!
eo_support
Posted: Wednesday, November 30, 2011 3:38:09 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

We have posted a new build that should fix this issue. Please see your private message for the download location.

Thanks!
Jeremy
Posted: Wednesday, November 30, 2011 5:43:36 PM
Rank: Newbie
Groups: Member

Joined: 11/29/2011
Posts: 4
Thanks, that appears to have solved the threadsafety issue. But it introduced a new problem. The way it is determining the Page cutoffs appears to have broken in this build.

So the top quarter to half an inch of page 2 appears at the bottom of page one. This is new behavior that didn't occur in the previous build I had.

eo_support
Posted: Wednesday, November 30, 2011 6:18:55 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

Can you post a test page so that we can take a look?

Thanks!
eo_support
Posted: Thursday, December 1, 2011 4:45:44 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,194
Hi,

The new build did change the paging algorithm from slightly above a text block’s top edge to exactly at the top of the text block’s top edge. This change was made because under certain scenarios adding additional space on top of the text line can cause other problems (for example, forcing table footer to the next page thus invalidates the previous calculated table layout). The change should not cause any problem for text because text lines are still honored. If it causes problem for you, please provide a sample and we will be happy to revisit the issue.

Alternatively, you can also apply “page-break-inside:avoid” on any element that you wish to avoid a page break.

Thanks!


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.