ASP.Net 2.0 Response.BinaryWrite

by Derek Pinkerton 26. May 2006 16:17

I couple of weeks ago I started getting involved with the User Inteface team on the new version of QualTrax, which is due out later this year.

In order to ensure any documents stored in QualTrax are as secure as possible they will all be stored outside of the web-root. This means that they will not be accessible outside of QualTrax. There will not be a direct URL to go to any document. The documents can be stored anywhere on the server, or on an entirely different server. This also means that we have to come up with some alternative means of sending the file to the user. A common method of doing this in the past would be to copy the document into the web directories, and then remove it after a predetermined amount of time had passed. While this does work, it is not the most secure method available, and it requires you have a service running in the background to clean up these files periodically.

A good alternative for this is to use the ASP.Net Response.WriteBinary method to send your file to the browser. Here is an example of this:

C#
Response.Clear();
Response.Buffer = true;
Response.ContentType = @"application/pdf";
System.IO.FileStream myFileStream = new System.IO.FileStream("Filename.PDF", System.IO.FileMode.Open);
long FileSize = myFileStream.Length;
byte[] Buffer = new byte[(int)FileSize];
myFileStream.Read(Buffer, 0, (int)FileSize);
myFileStream.Close();
Response.BinaryWrite(Buffer);
Response.Flush();
Response.End();

This code is in an aspx page that I send in my document ID as the only parameter. So to bring up the document my url would look something like "showdocument.aspx?ID=XXX"

In a perfect world this would work as expected on all browsers, however we all know that this isn't a perfect world so as you might guess I had some problems with it. In particular Internet Explorer (who would have thought) has a problem with this. In researching this problem a co-worker (Vicky Herrala) came across this microsoft knowledgebase article, which points the blame at a script not returning a "content-length" header. We found that you can add this header by adding the following line to the code above.

Response.AddHeader("Content-Length", FileSize.ToString());

After adding this line, I tested again only to find that IE still had problems with this. Firefox renders it perfectly. ;) Looking into this further we found an msdn article that explains how IE decides how it should open the file. According to this article IE should be looking at "The server-supplied MIME type, if available." As you can see in the above snippet, we have specified the content type and yet IE still cannot render this document correctly. The msdn article also mentions that IE will examine the URL in an attempt to determine the content type. In order to fool Internet Explorer into realizing that this is in fact a PDF document I added a dummy parameter to my url that puts in a fake document name with the appropriate extension. My url now looks like "showdocument.aspx?ID=XXX&doc=test.pdf" I fired this up and was presented with my PDF!

I know there has to be a better way to do this so if anyone out there finds a suitable replacement please let me know, but as for now this is working.

Tags: , ,

Comments

6/24/2009 11:16:33 PM #

Use Response.OutputStream.Write(.... instead of BinaryWrite and it should work no need to put fake querystrings!

Ketul |

6/24/2009 11:16:33 PM #

Another neat thing that this workaround appears to fix is embedding multimedia within HTML documents.

Instead of using a filename for multimedia references, you can point a link or reference in an HTML document to an .ASPX page which will be responsible for retrieving and returning the file your way.  

For example:

<IMG SRC="GetMultimedia.aspx?ID=12">


When the browser is processing the HTML syntax-- it goes to the GetMultimedia page which uses Response.WriteBinary to send the appropriate image down.

This worked wonderfully for images (GIFs, JPGs, PNG, etc).  However, it was very picky with the syntax used for video and sound.  

For example
<bgsound src="GetMultimedia.aspx?ID=6" loop="-1"> would work but <EMBED PALETTE="#000000|#FFFFFF"  width=450 height=383 SRC="GetMultimedia.aspx?ID=6" autostart=false> would not.

Well it turns out, Derek's extension find allows us to bypass that discrepancy.  By putting a fake parameter in the URL with the the extension, the multimedia shows up and plays as expected:

<EMBED PALETTE="#000000|#FFFFFF"  width=450 height=383 SRC="GetMultimedia.aspx?ID=6&Doc=Doc.MP3" autostart=false>

Vicky |

Comments are closed