views:

1334

answers:

4

I'm creating a PDF file on the fly using ITextSharp and ASP.NET 1.1. My process is as follows -

  • Create file on server
  • Redirect browser to newly created PDF file so it is displayed to user

What I'd like to do is delete the PDF from the server as soon it is displayed in the users browser. The PDF file is large so it is not an option to hold it in memory, an initial write to the server is required. I'm currently using a solution that periodically polls for files then deletes them, but I'd prefer a solution that deletes the file immediately after it has been downloaded to the client machine. Is there a way to do this?

+4  A: 

Instead of redirecting the browser to the created file you could serve the file yourself using you own HttpHandler. Then you could delete the file immediately after you served it or you could even create the file in memory.

Write the PDF file directly to the Client:

public class MyHandler : IHttpHandler {
    public void ProcessRequest(System.Web.HttpContext context) {
        context.Response.ContentType = "application/pdf";
        // ...
        PdfWriter.getInstance(document, context.Response.OutputStream);
        // ...

or read an already generated file 'filename', serve the file, delete it:

context.Response.Buffer = false;
context.Response.BufferOutput = false;
context.Response.ContentType = "application/pdf";

Stream outstream = context.Response.OutputStream;
FileStream instream = 
    new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);

byte[] buffer = new byte[BUFFER_SIZE];
int len;
while ((len = instream.Read(buffer, 0, BUFFER_SIZE)) > 0) {
    outstream.Write(buffer, 0, len);
}
outstream.Flush();
instream.Close();

// served the file -> now delete it 
File.Delete(filename);

I didn't try this code. This is just how I think it would work ...

f3lix
+2  A: 

Inspired by f3lix's answer (thanks f3lix!) I've come up with the folowing VB.net code -

HttpContext.Current.Response.ClearContent()
HttpContext.Current.Response.ClearHeaders()
HttpContext.Current.Response.ContentType = "application/pdf"
HttpContext.Current.Response.TransmitFile(PDFFileName)
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.Close()
File.Delete(PDFFileName)

This appears to work - is the 'WriteFile' method I've used any less efficent that the stream methods used by f3lix? Is there a method available that's more efficient than either of our solutions?

EDIT (19/03/2009) Based on comments below I've changed 'WriteFile' method to 'TransmitFile' as it appears it sends the file down to client in chunks rather than writing the entire file to the webserver's memory before sending. Further info can be found here.

ipr101
You should use TransmitFile instead. WriteFile loads the entire file into memory - TransmitFile streams it.
Mark S. Rasmussen
Furthermore, setting Response.Buffer = true kinda goes against TransmitFile, though I'm not sure if TransmitFile will ignore the Buffer parameter.
Mark S. Rasmussen
A: 

The solution:

Response.TransmitFile(PDFFileName)
Response.Flush()
Response.Close()
File.Delete(PDFFileName)

Simply doesn't work for me (file never makes it to client). Reading in a byte array and calling Response.BinaryWrite isn't an option either since the file may be large. Is the only hack for this to start an asynchronous process that waits for the file to be released and then delete it?

dudeNumber4
A: 

Or you could just return it to the browser without writing to disk at all:

byte[] pdf;

using (MemoryStream ms = new MemoryStream()) {
    Document doc = new Document();
    PdfWriter.GetInstance(doc, ms);
    doc.AddTitle("Document Title");
    doc.Open();
    doc.Add(new Paragraph("My paragraph."));
    doc.Close();
    pdf = ms.GetBuffer();
}

Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=MyDocument.pdf");
Response.OutputStream.Write(pdf, 0, pdf.Length);
michael.rp