Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is contaminating this switch statement?

I have a system which is doing following,

  • Upload documents to SharePoint
  • Event receiver will add job to DB, Create a folder for job in Document Conversion Directory
  • A directory watcher will trigger Document Conversion windows service
  • Windows service will get batch of 10 jobs from DB (using main thread)
  • On start Windows service creates X number of threads based on processor's cores (using Parallel For)
  • Then creates worker thread with timeouts for every db jobs (this is different from parallel For threads)
  • and it carries on...
  • Oh while converting... in worker threads.. we are calling ActiveDirectory, logging to DB (Read, Write) and uploading document back to SharePoint

I manage to break it... if I upload a password protected document... and soon after upload a powerpoint document, powerpoint document throws password incorrect exception etc..

but if there's gap inbetween both documents even 60 seconds, it all works fine which means powerpoint document does converts to PDF.

Following is the code but I had to trim unnecessary parts out of it,

Here is the main class where things start from,

 Parallel.For(0, noOfThreadsToRunOnPDFServer, new ParallelOptions { MaxDegreeOfParallelism = noOfThreadsToRunOnPDFServer },
    i =>
    {
        this.docConvService.ProcessDocuments(i);
    });

Then the conversion is happening here...

using System;
using System.IO;
using System.Runtime.ExceptionServices;
using System.Threading;

namespace PDFService
{
    public class AsposePDFConverter : IPDFConverter
    {
        private IDocConversionSettings settings;
        private ExceptionDispatchInfo conversionException = null;
        public enum SupportedExtensions
        {
            Doc,
            Docx,
            Xls,
            Xlsx,
            Pdf,
            Pps,
            Ppsx,
            Ppt,
            Pptx,
            Txt,
            Html,
            Mhtml,
            Xhtml,
            Msg,
            Eml,
            Emlx,
            One,
            Vsd,
            Vsdx,
            Vss,
            Vssx
        }

        public AsposePDFConverter(IDocConversionSettings settings)
        {
            this.settings = settings;
        }

        private void SyncThreadStartWithTimeout(ThreadStart threadStart, TimeSpan timeout)
        {
            Thread workerThread = new Thread(threadStart);
            workerThread.Start();

            bool finished = workerThread.Join(timeout);
            if (!finished)
            {
                workerThread.Abort();
                throw new ConversionTimeoutException("PDF Conversion exceeded timeout value");
            }
        }

        public MemoryStream ConvertToPDF(string documentName, Stream docContent, double timeoutMS)
        {
            this.conversionException = null;

            MemoryStream outStream = null;
            MemoryStream inStream = new MemoryStream();
            docContent.CopyTo(inStream);
            inStream.Seek(0, SeekOrigin.Begin);

            SupportedExtensions documentExtension;
            string szExtension = Path.GetExtension(documentName).TrimStart('.');
            if (Enum.TryParse(szExtension, true, out documentExtension))
            {
                switch (documentExtension)
                {
                    case SupportedExtensions.Doc:
                    case SupportedExtensions.Docx:
                    case SupportedExtensions.Txt:
                    case SupportedExtensions.Html:
                    case SupportedExtensions.Mhtml:
                    case SupportedExtensions.Xhtml:
                        SyncThreadStartWithTimeout(
                                () => { outStream = ConvertWordsToPDF(inStream); },
                                TimeSpan.FromMilliseconds(timeoutMS));
                        break;
                    case SupportedExtensions.Pps:
                    case SupportedExtensions.Ppsx:
                    case SupportedExtensions.Ppt:
                    case SupportedExtensions.Pptx:
                        SyncThreadStartWithTimeout(
                                () => { outStream = ConvertSlidesToPDF(inStream); },
                                TimeSpan.FromMilliseconds(timeoutMS));
                        break;
                }

                // Conversion happens on sub-threads so they can time out, if they throw an exception, throw it from this thread
                if (this.conversionException != null)
                    this.conversionException.Throw();

                return outStream;
            }
            else
            {
                throw new FormatNotSupportedException("Document type is not supported");
            }
        }

        private MemoryStream ConvertWordsToPDF(Stream docContent)
        {
            try
            {
                Aspose.Words.License lic = new Aspose.Words.License();
                lic.SetLicense(this.settings.AsposeLicensePath);
                Aspose.Words.Document doc = new Aspose.Words.Document(docContent);

                MemoryStream stream = new MemoryStream();
                doc.Save(stream, Aspose.Words.SaveFormat.Pdf);
                return stream;
            }
            catch (Exception ex)
            {
                this.conversionException = ExceptionDispatchInfo.Capture(ex);
                return null;
            }
        }

        private MemoryStream ConvertSlidesToPDF(Stream docContent)
        {
            try
            { 
                Aspose.Slides.License lic = new Aspose.Slides.License();
                lic.SetLicense(this.settings.AsposeLicensePath);
                using (Aspose.Slides.Presentation presentation = new Aspose.Slides.Presentation(docContent))
                {
                    MemoryStream stream = new MemoryStream();
                    presentation.Save(stream, Aspose.Slides.Export.SaveFormat.Pdf);
                    return stream;
                }
            }
            catch (Exception ex)
            {
                this.conversionException = ExceptionDispatchInfo.Capture(ex);
                return null;
            }
        }

    }
}

Error is,

Error during Document PDF Conversion. Details are: PDFConversionID: 6061, DocumentName: powerpoint.ppsx, WebURL: REMOVED, UploadedBy: REMOVED, ConversionDuration: 00:01:06.3072410

Aspose.Words.IncorrectPasswordException: The document password is incorrect. at Aspose.Words.Document. (Stream , LoadOptions )
at Aspose.Words.Document. (Stream , LoadOptions ) at DocumentPDFConversionService.AsposePDFConverter.ConvertWordsToPDF(Stream docContent) in...

As you can see there is something very fishy going on

like image 571
Mathematics Avatar asked Jan 28 '26 02:01

Mathematics


1 Answers

You are using the same instance of this.docConvService in multiple threads, so your conversionException property is probably written by the password-protected doc while your other document is processing. You should instanciate a new instance of your AsposePDFConverter, or change the way you return exceptions, e.g. in a result-object returned by ConvertToPDF, that contains a MemoryStream and your error.

Seperate instance for each request :

Parallel.For(0, noOfThreadsToRunOnPDFServer, new ParallelOptions { MaxDegreeOfParallelism = noOfThreadsToRunOnPDFServer },
    i =>
    {
        new AsposePdfConverter(settings).ProcessDocuments(i);
    });

Returning a result-object :

 public ConversionResult ConvertToPDF(string documentName, Stream docContent, double timeoutMS)
{
    /** Your code **/
    return new ConversionResult() 
        {
        MemoryStream = memoryStream,
        ConversionException = conversionException
        };
}

class ConversionResult {
    MemoryStream MemoryStream {get;set;}
    ExceptionDispatchInfo ConversionException {get;set;}
}
like image 57
Christoph Sonntag Avatar answered Jan 29 '26 15:01

Christoph Sonntag



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!