I'm using C# and ASP.NET 2.5.
I want a simple way to generate a "file" on-the-fly (let's say a csv file for this example) and transmit it to the client without actually writing it to the server file system.
After some searching and trial and error, I developed the following. It seems to fit the bill exactly. It should be very easily adaptable to PHP or any other server-side software since it mostly involves modifying headers.
protected void streamToResponse()
{
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=testfile.csv");
Response.AddHeader("content-type", "text/csv");
using(StreamWriter writer = new StreamWriter(Response.OutputStream))
{
writer.WriteLine("col1,col2,col3");
writer.WriteLine("1,2,3");
}
Response.End();
}
May I also suggest, that if you have something other than text, say, binary, you use the Response.WriteBinary() method
I've often created a JPG on the fly, wrote it to a MemoryStream using the Bitmap.Save() method, turned the MemoryStream into a byte[] array using .ToArray() and then Response.WriteBinary() that array.
Use the MemoryStream Class:
http://msdn.microsoft.com/en-us/library/system.io.memorystream.aspx
Related
I am trying to use a LibTiff.Net library and rewriting a merge tool TiffCP api to use memory streams.
This library has a Tiff class and by passing a stream to this class, it can merge tiff images into this stream.
For testing, I passed on a Filestream and I got what i wanted - it merged and I was able to see multipage tif.
But when I pass a MemoryStream, I am able to verify that the page data is being added to the stream as I loop through but when I write it to the file at the end, I could see only 1st page.
var mso = new MemoryStream();
var fso = new FileStream(#"C:\test\ttest.tif",FileMode.OpenOrCreate); //This works
using (Tiff outImage = Tiff.ClientOpen("custom", "w", mso, tso))
{
//...
//..
System.Drawing.Image tiffImg = System.Drawing.Image.FromStream(mso, true);
tiffImg.Save(#"C:\test\test2.tiff", System.Drawing.Imaging.ImageFormat.Tiff);
tiffImg.Dispose();
//..
//..
}
P.S: I need it in memorystream because, of some folder permissions on servers + vendor API reasons.
You probably using the memory stream before data is actually written into the stream.
Please use Tiff.Flush() method before accessing data in the memory stream. And please make sure you call Tiff.WriteDirectory() method for each page you create.
EDIT:
Please also take a look at Bob Powell's article on Generating Multi-Page TIFF files. The article shows how to use EncoderParameters to actually generate a multipage TIFF.
Using
tiffImg.Save(#"C:\test\test2.tiff", System.Drawing.Imaging.ImageFormat.Tiff);
you are probably save only first frame.
I created the functionality to edit the existing PDf content(adding some text and images) and after that i am opening this pdf file for print or download and i am using this code
Pdf is not getting open some time after BinaryWrite
byte[] outBuf = outStream1.GetBuffer();
HttpContext.Current.Response.Expires = 0;
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename="test.pdf");
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.ContentEncoding = new System.Text.UTF8Encoding();
HttpContext.Current.Response.BinaryWrite(outBuf);
outStream.Close();
HttpContext.Current.Response.End();
It is working fine on local machine or development server and some time on server.
On server after some times it is opening blank page. And after browser cache clear or temp file clear it works
I am not getting it where is the problem may be some client browser memory problem.
But if it is browser memory issue the it should also come on local too because I am using the same browser.
Please give me some idea or solution so that I can sort our this thing.
The GetBuffer method only returns exactly the content of the memory stream if it was created as a readonly stream from an array of bytes to begin with. Otherwise it returns the internal buffer, which may contain unused bytes at the end.
Use the ToArray method to get exactly the content of the memory stream, and nothing more:
byte[] outBuf = outStream1.ToArray();
Another thing that triggers some browsers some of the time to treat your stream as PDF, is to append some dummy argument to your URL so that it ends with ".pdf". I am not sure if this is really necessary in your case since your are setting the 'content-disposition' to 'attachment'. It won't hurt though.
I have this code to extract a table to computer in a .xls file:
// I have a string which contains HTML table codes, named as excelTable
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.AddHeader("Content-Disposition", String.Format("Attachment;Filename=file.xls", ));
response.Buffer = true;
response.ContentEncoding = System.Text.Encoding.Default;
response.ContentType = "application/vnd.ms-excel";
response.Write(excelTable);
response.End();
And I have seen that this is not a real .xls file. I can open it in Notepad and see my standart html table codes.
Now I understand that defining ContentType is not enough. So what else can I do to generate a pure .xls or .xlsx file? Or Should I certainly use Excel Libraries like OpenXML, Interop, etc. ?
Actual XLS/XLSX data must be sent back - that is, data generated with a library (e.g EEPlus) or other suitable source.
This common hack/approach works because Excel "knows how to read HTML". It doesn't actually turn the HTML into XSL/XLSX, although it can be saved as new spreadsheet once loaded by Excel.
Changing the content type will have no effect on the data, and instead will effectively stop this approach from working: the content type is used for associating the program (i.e. Excel) which will be used to open/read the data.
So yes: to generate a real XLS/XLSX document, use a library.
I have a process that creates a PDF. I want these PDF's to be temporary and short lived. I want to be able to perform the following when the user clicks a button:
string CreatePDF()//returns fileName.pdf
PromptUserToDownloadPDF()
DeletePDF(fileName.pdf)
I want to avoid having to create a cleanup procedure and deal with any race conditions that arise from users concurrently creating PDF's while running cleanup.
In winforms, I would synchronously prompt a user to download a file. How can I do a similar task in web?
UPDATE
Please note that I am using a 3rd party app to create the PDF's (Apache FOP). Basically I (will) have a function that invokes the command line:
C:>fop "inputfile" "output.pdf"
So, in memory is not an option...that is unless I could somehow do like....
string CreatePDF()//returns fileName.pdf
string RecreatePDFInMemory()
DeletePDF(fileName.pdf)
PromptUserToDownloadPDF()
Something like this:
byte[] _pdfbytes = CreatePDF();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-Length", _pdfbytes.Length.ToString());
Response.BinaryWrite(_pdfbytes);
Since this creates the PDF in memory, you don't need to worry about cleanup.
Edit for OP's edit:
From within CreatePDF, You can use Path.GetTempFileName to create a temp file and execute "fop" to write to that file. Delete that file immediately before returning the byte[]. I recommend doing this delete inside of a finally block. However, "Fop" does support having its output piped to stdout. Having the CreatePDF function grab that is probably cleaner.
Look into doing something along these lines.
Similar to what someone referred to in a different answer, you don't need to save the PDF file on your system, you can just send it as a response.
I'm not sure how you're creating your PDF, but try looking into this below and seeing if your process could use something like this.
HttpResponse currentResponse = HttpContext.Current.Response;
currentResponse.Clear();
currentResponse.ClearHeaders();
currentResponse.ContentType = "application/pdf";
currentResponse.AppendHeader("Content-Disposition", "attachment; filename=my.pdf");
//create the "my.pdf" here
currentResponse.Flush();
currentResponse.End();
Not sure of your process but you should be able to write the PDF to a byte[] and skip writing to the disk altogether.
byte[] pdf = GetPDFBytes(filename)
MemoryStream pdfStream = new MemoryStream(pdf);
Then use the pdfStream to send back to a user.
You can stream out a file with an asp.net page.
I tried to find very old article for you which demonstrates this with a GIF (there's not an actual file)
http://www.informit.com/articles/article.aspx?p=25487
It makes a special page which streams out the data (sets content type appropriately in the header).
Similarly, you can make a "page" to stream out the PDF - it might not even need to ever reside on disk, but if it did, you could delete it after streaming it to the browser.
I have a stream object in which I have some document, I know what document is it, how can I open that document without saving it into a file physically. So I want to directlly open the document from stream itself without saving it.
How to do that? I doing it in c#
this is how i do such a thing, but i know the file's name. this is method is called into an empty aspx page (i mean without any kind of html markup except the <#Page ... /> line )
private void LoadAttachment()
{
byte[] ImageData = ... get data from somewhere ...
Response.Buffer = true;
String filename = "itakethis.fromdatabase";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
Response.ContentType = GetMimeType(filename);//you can try to extrapolate it from file extension
if(ImageData.Length > 0)
Response.BinaryWrite(ImageData);
else
Response.BinaryWrite(new byte[1]);
Response.Flush();
ApplicationInstance.CompleteRequest();
}
`
You can use MemoryStream to use the document only in RAM.
Unfortunately most programs (Word, Excel, Notepad, ...) need a filename to open a file. So i think there is no real solution to your problem.
The only think would be to write a File System Filter Driver, that returns the MemoryStream for a virtual filename, but that driver has to be written in C++ and is not the easiest one to do.
Why can't you save the file?
I've used GetTempFilename to good effect in the past. I can't remember exactly which class it's in, probably System.Environment or File itself. Anyway, you can be sure the file will be in the system defined temp folder, so you can safely delete the file once you're done with it.