views:

263

answers:

4

Hi,

I'm making tests with ASP.NET HttpHandler for download a file writting directly on the response stream, and I'm not pretty sure about the way I'm doing it. This is a example method, in the future the file could be stored in a BLOB in the database:

        public void GetFile(HttpResponse response)
    {
        String fileName = "example.iso";
        response.ClearHeaders();
        response.ClearContent();
        response.ContentType = "application/octet-stream";
        response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName);
        using (FileStream fs = new FileStream(Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data"), fileName), FileMode.Open))
        {
            Byte[] buffer = new Byte[4096];
            Int32 readed = 0;

            while ((readed = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                response.OutputStream.Write(buffer, 0, readed);
                response.Flush();
            }
        }
    }

But, I'm not sure if this is correct or there is a better way to do it. My questions are:

  1. When I open the url with the browser, appears the "Save File" dialog... but it seems like the server has started already to push data into the stream before I click "Save", is that normal?
  2. If I remove the line"response.Flush()", when I open the url with the browser, ... I see how the web server is pushing data but the "Save File" dialog doesn't come up, (or at least not in a reasonable time fashion) why?
  3. When I open the url with a WebRequest object, I see that the HttpResponse.ContentLength is "-1", although I can read the stream and get the file. What is the meaning of -1? When is HttpResponse.ContentLength going to show the length of the response? For example, I have a method that retrieves a big xml compresed with deflate as a binary stream, but in that case... when I access it with a WebRequest, in the HttpResponse I can actually see the ContentLength with the length of the stream, why?
  4. What is the optimal length for the Byte[] array that I use as buffer for optimal performance in a web server? I've read that is between 4K and 8K... but which factors should I consider to make the correct decision.
  5. Does this method bloat the IIS or client memory usage? or is it actually buffering the transference correctly?

Sorry for so many questions, I'm pretty new in web development :P

Cheers.

+1  A: 
  1. Yes, it is buffering.
  2. Flush pushes the cached content to the browser. If it is never pushed, you won't get a save dialog box.
  3. Hard to tell without seeing the exact files/URLs/Streams you are using.
  4. I think the factors depends on how sluggish your page is, really. You will have better performance toward 4k. And perhaps, the lower value will be better to accommodate slower connections.
  5. See #1 & 2.
TheGeekYouNeed
Thanks all, you clear all my doubts. I'm glad I joined this community :D
vtortola
+2  A: 

For #3 you need to set the content-length header in your http-response. Many of those values come from http headers.

I believe you can change the bufferring by changing a buffering property on the response object to false. Haven't done it in a while so I don't remember what it might be.

Min
Thanks all, you clear all my doubts. I'm glad I joined this community :D
vtortola
+3  A: 
  1. Yes; this is normal.
  2. If you never flush, the browser doesn't get any response until the serever finishes (Not even the Content-Disposition header). Therefore, it doesn't know to show a file dialog.
  3. The Content-Length header only gets set if the entire response is buffered (If you never flush) or if you set it yourself. In this case, you can and should set it yourself; write

    response.AppendHeader("Content-Length", new FileInfo(path).Length);
    
  4. I recommend 4K; I don't have any hard basis for the recommendation.
  5. This method is the best way to do it. By calling Flush inside the loop, you are sending the response down the wire immediately, without any buffering. However, for added performance, you can use GZIP compression.
SLaks
Thanks all, you clear all my doubts. I'm glad I joined this community :D
vtortola
+1  A: 

Check my blog post here about compressing response streams using gzip compression

James Westgate
That's very interesting, I will use it. I was using the "traditional" way, but that one is much better!
vtortola