1

This is my code which is used in a wcf service. It successfully generates the PDF, but after generating the document, the folder in which the PDF is generated gives the error: "access is denied"

The PDF is closed for the website, but for the continuous web service it is not closed.

string r = builder.ToString();
string pdfname = Fuhre + "_" + ProtokolType + "_" + GeraeteNr + "_" + r;

PdfWriter.GetInstance(document, new FileStream(@"C:\inetpub\wwwroot\protokoll_pdfs\"+pdfname+".pdf",FileMode.Create));
document.Open();
WebClient wc = new WebClient();
string htmlText = html;
//Response.Write(htmlText);
List<IElement> htmlarraylist = HTMLWorker.ParseToList(new StringReader(htmlText), null);
for (int k = 0; k < htmlarraylist.Count; k++)
{
   document.Add((IElement)htmlarraylist[k]);
}

pdflink1 = pdfname + ".pdf";
htmlpdflink =""+pdflink1;
document.Close();
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • "Access is denied" is not the same as "not able to close." It means that the access to the file is denied. Your question is wrong. Also: why are you creating the PDF as a file? What if people concurrently create the same file? In that case, you are in big trouble. Please don't blame your bad coding practices on iTextSharp. – Bruno Lowagie Apr 17 '15 at 12:52
  • I have updated your question, but the question is still unclear. What do you mean when you say "The folder gives the error *Access is denied*"? A folder in itself doesn't throw such an error. What are you trying to do with the folder? Also: it is not clear what you mean when you say "The PDF is closed for the website, but for the continuous web service it is not closed." Are you saying that the PDF is locked? That could very well be caused by your choice to create the files on disk. How do you make sure that 2 different users don't try to write to the same file? – Bruno Lowagie Apr 17 '15 at 12:57
  • yes sir i am the beginner, in short word , pdf was successfully generated but when i closed the wcf service than i am able to read the pdf , while running the wcf service i am not able to open . this is the error " your file is used by another program." it means wcf sevice continuing open and work on this pdf file . thanks in advance –  Apr 17 '15 at 13:03
  • Do you need the file on disk? – Bruno Lowagie Apr 17 '15 at 13:09
  • 1
    The problem is that the PdfWriter class still has a handle to the file. Wrap it in a "using" clause. – BDH Apr 17 '15 at 13:12
  • I have added an answer. Can you try that code and let me know the results. – Praveen Paulose Apr 17 '15 at 13:14
  • I'm a Java developer, not a C# developer, but what @BDH says, seems more reasonable that the answer that was provided. – Bruno Lowagie Apr 17 '15 at 13:19
  • Bruno Lowagi sir : yes sir i need that file on disk . –  Apr 17 '15 at 13:22
  • BDH : wrap it in a "using" not work –  Apr 17 '15 at 13:29
  • You may need to create your filestream outside of the GetInstance call and implement the using pattern on that as well to make sure that it is disposed as well. (Answer added below.) – BDH Apr 17 '15 at 13:41
  • i just want to do , my service was not closed but after generation of file pdf is successfully created because i mail that file. in the mail attachment i can see all the data .. i am not able to see that file without closing my wcf sevice. i have to stop my service to see the file . i just want to know how can i see the file with out interpreting or closing the file . that is my aim –  Apr 17 '15 at 13:52
  • Post the code used in the web service to send email. I bet you're using [MailMessage](https://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.aspx), which implements [IDisposable](https://msdn.microsoft.com/en-us/library/system.idisposable.aspx). If so that's probably what's holding on to `FileStream`. (PDF) You need to either: [1] wrap the `MailMessage` instance in a `using` block, or [2] explicitly call `MailMessage.Dispose()`. [A simple example here](http://kuujinbo.info/iTextSharp/pdfSendMail.aspx). – kuujinbo Apr 18 '15 at 03:25

4 Answers4

2

You need to be careful to dispose of everything.

    using(var filesStream = new FileStream())
    {
        using(PdfWriter wri = PdfWriter.GetInstance(doc, fileStream)) 
        {
    ...
        }
    }
BDH
  • 156
  • 8
  • I think this is indeed the way to go. – Bruno Lowagie Apr 17 '15 at 13:45
  • i just want to do , my service was not closed but after generation of file pdf is successfully created because i mail that file. in the mail attachment i can see all the data .. i am not able to see that file without closing my wcf sevice. i have to stop my service to see the file . i just want to know how can i see the file with out interpreting or closing the file . that is my aim –  Apr 17 '15 at 13:52
0

There are a few other objects (Stream, Document) you may want to close. A sample of how to perform the operation is shown below.

FileStream stream = new FileStream(filePath, FileMode.CreateNew);            
Document doc = new Document(PageSize.A4, 24, 24, 24, 24);
PdfWriter writer = PdfWriter.GetInstance(doc, stream);

doc.Open();

//PDF writing operations here


writer.Flush();
doc.Close();
writer.Close();
stream.Close();
Praveen Paulose
  • 5,741
  • 1
  • 15
  • 19
  • @BrunoLowagie For your benefit read this link http://api.itextpdf.com/itext/com/itextpdf/text/pdf/PdfWriter.html. Please check the section Methods inherited from class com.itextpdf.text.DocWriter where you may just see a flush. This code sample put here is from a live project and it works perfect. You may want to try the code before shooting.. – Praveen Paulose Apr 17 '15 at 13:13
  • OK, I overlooked that method. I wrote those classes 15 years ago. I can't remember anything (for your benefit take a look at my profile). Anyway: if you consult the code, you'll see that `doc.Close()` cause a chain of events that closes the `writer` as well as the `stream`. – Bruno Lowagie Apr 17 '15 at 13:16
  • @BrunoLowagie Just checked your profile :) and doubted my own code. Awesome library by the way. – Praveen Paulose Apr 17 '15 at 13:17
  • Thanks, I think that @BDH's answer is the real solution. – Bruno Lowagie Apr 17 '15 at 13:19
  • @BrunoLowagie Wouldn't the writer.close do exactly what BDH has mentioned, in a different way. – Praveen Paulose Apr 17 '15 at 13:20
  • The problem isn't that the stream isn't closed, the problem is that the file is *in use*. As long as the `PdfWriter` isn't garbage collected (I don't know how this is called in C#), it's possible that there's still a file hander active. (DISCLAIMER: I don't know anything about C#.) Anyway: why would you create a file on disk if you're writing a web service? – Bruno Lowagie Apr 17 '15 at 13:24
  • @BrunoLowagie I have been using a service where I need it on disk, so that it can be sent as an email later or if it is a time consuming process to create a pdf, i create it once and going forward just return the file from disk. – Praveen Paulose Apr 17 '15 at 13:27
  • Praveen Paulose : not work i am not able to add any string in to the pdf.it shows is corrupted –  Apr 17 '15 at 13:37
0

You want to serve a file to a browser and/or you want to save the file on disk.

In that case, you would benefit from creating the file in memory and then send the bytes to the browser as well as to a file on disk. This is explained in the answer to the following question: Pdf file not loading properly created by the servlet

The answer mentioned above is written in Java, so you'll have to adapt it.

You can do so by looking at other examples. For instance: Create PDF in memory instead of physical file

byte[] pdfBytes; using(var mem = new MemoryStream()) { using(PdfWriter wri = PdfWriter.GetInstance(doc, mem)) { doc.Open();//Open Document to write Paragraph paragraph = new Paragraph("This is my first line using Paragraph."); Phrase pharse = new Phrase("This is my second line using Pharse."); Chunk chunk = new Chunk(" This is my third line using Chunk.");

    doc.Add(paragraph);

    doc.Add(pharse);

    doc.Add(chunk); 
}
pdfBytes = mem.ToArray();

}

Now you can write the pdfBytes to the Response object in your web application:

private void ShowPdf(byte[] strS)
{
    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = "application/pdf";
    Response.AddHeader("Content-Disposition", "attachment; filename=" + DateTime.Now);

    Response.BinaryWrite(strS);
    Response.End();
    Response.Flush();
    Response.Clear();
}

And you can reuse the bytes to write them to a File: Can a Byte[] Array be written to a file in C#?

File.WriteAllBytes(string path, byte[] bytes)

If the problem persist, then you know that it isn't caused by iTextSharp, because iTextSharp merely produces the bytes.

Community
  • 1
  • 1
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
0

In addition to what everyone else said, I strongly recommend you break each process into multiple sections that don't interact and aren't even aware of each other. Then test each section independently as much as possible. For instance:

private void makePDF( filePath )
{
    //Create the PDF
}

private void main()
{
    //Make the PDF
    makePDF( "test.pdf" );

    //If this line fails then your makePDF code has an open handle
    File.Delete( "test.pdf" );
}

Then continue:

private void makePDF( filePath )
{
    //Create the PDF
}

private void emailPDF( filePath )
{
    //Email the PDF
}

private void main()
{
    //Make the PDF
    makePDF( "test.pdf" );
    emailPDF( "test.pdf" );

    //If this line fails now then your emailPDF code has an open handle
    File.Delete( "test.pdf" );
}

The important part if that you don't try 500 things all at once because that leads to "something is locking my file but I don't know what".

Chris Haas
  • 53,986
  • 12
  • 141
  • 274