35

What's the best way to stream files using ASP.NET?

There appear to be various methods for this, and I'm currently using the Response.TransmitFile() method inside an http handler, which sends the file to the browser directly. This is used for various things, including sending FLV's from outside the webroot to an embedded Flash video player.

However, this doesn't seem like a reliable method. In particular, there's a strange problem with Internet Explorer (7), where the browser just hangs after a video or two are viewed. Clicking on any links, etc have no effect, and the only way to get things working again on the site is to close down the browser and re-open it.

This also occurs in other browsers, but much less frequently. Based on some basic testing, I suspect this is something to do with the way files are being streamed... perhaps the connection isn't being closed properly, or something along those lines.

After trying a few different things, I've found that the following method works for me:

Response.WriteFile(path);
Response.Flush();
Response.Close();
Response.End();

This gets around the problem mentioned above, and viewing videos no longer causes Internet Explorer to hang.

However, my understanding is that Response.WriteFile() loads the file into memory first, and given that some files being streamed could potentially be quite large, this doesn't seem like an ideal solution.

I'm interested in hearing how other developers are streaming large files in ASP.NET, and in particular, streaming FLV video files.

Faizan Mubasher
  • 4,427
  • 11
  • 45
  • 81
Mun
  • 14,098
  • 11
  • 59
  • 83
  • Here's an approach I used which adds resumable download functionality which would be useful if streaming video: http://stackoverflow.com/a/6475414/222748 – Michael Nov 14 '14 at 13:24

4 Answers4

51

I would take things outside of the "aspx" pipeline. In particular, I would write a ran handler (ashx, or mapped via config), that does the minimum work, and simply writes to the response in chunks. The handler would accept input from the query-string/form as normal, locate the object to stream, and stream the data (using a moderately sized local buffer in a loop). A simple (incomplete) example shown below:

public void ProcessRequest(HttpContext context) {
    // read input etx
    context.Response.Buffer = false;
    context.Response.ContentType = "text/plain";
    string path = @"c:\somefile.txt";
    FileInfo file = new FileInfo(path);
    int len = (int)file.Length, bytes;
    context.Response.AppendHeader("content-length", len.ToString());
    byte[] buffer = new byte[1024];
    Stream outStream = context.Response.OutputStream;
    using(Stream stream = File.OpenRead(path)) {
        while (len > 0 && (bytes =
            stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            outStream.Write(buffer, 0, bytes);
            len -= bytes;
        }
    }
}
JohnFx
  • 34,542
  • 18
  • 104
  • 162
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    A downvote without a reason doesn't help anybody. I thought that your answer was good. +1 to bring you back to parity. – Guy Mar 06 '09 at 16:43
  • I'm not the one who downvoted, but thought I'd point out that the initial question does actually state the code is being used in an http handler... Thanks for the suggestion anyway though. – Mun Mar 06 '09 at 19:09
  • 1
    To change name of the file, after line: `context.Response ...` add this line: `context.Response.AppendHeader("content-Disposition", "attachment;filename="+filename);` – MaciejLisCK Jan 16 '13 at 11:47
  • @MarcGravell should have explained why Response.Buffer is the rock to your Response.Flush's paper in his response. – JJS Sep 13 '13 at 16:16
  • What would be the "Content-Type" for Video FLV file? – Faizan Mubasher Oct 27 '14 at 05:54
  • Yeah! Got it. I have written your code as it is but stuck with another issue. How to assign this stream response to my html video control or any other control? – Faizan Mubasher Oct 27 '14 at 07:13
  • @FaizanMubasher video streaming is usually a bit more complicated than static content... – Marc Gravell Oct 27 '14 at 07:15
  • This is working! But here is another issue, I am playing video file through stream, video runs only once. How to replay video? – Faizan Mubasher Oct 28 '14 at 04:26
  • @FaizanMubasher giving full details of video streaming is not something that is best-answered in comments on an largely-unrelated post – Marc Gravell Oct 28 '14 at 08:27
10

Take a look at the following article Tracking and Resuming Large File Downloads in ASP.NET which will give you more in depth than just open a stream and chuck out all the bits.

The http protocol supports ranged byte requests and resumeable downloads, and many streaming clients (like video players or Adobe pdf) can and will try to chunk these up, saving bandwidth and giving your users a better experience.

Not trivial, but it's time well spent.

Robert Paulson
  • 17,603
  • 5
  • 34
  • 53
8

Try opening the file as a stream, then using Response.OutputStream.Write(). For example:

Edit: My bad, I forgot that Write takes a byte buffer. Fixed

byte [] buffer = new byte[1<<16] // 64kb
int bytesRead = 0;
using(var file = File.OpenRead(path))
{
   while((bytesRead = file.Read(buffer, 0, buffer.Length)) != 0)
   {
        Response.OutputStream.Write(buffer, 0, bytesRead);
   }
}
Response.Flush();
Response.Close();
Response.End();

Edit 2: Did you try this? It should work.

bdukes
  • 152,002
  • 23
  • 148
  • 175
Randolpho
  • 55,384
  • 17
  • 145
  • 179
  • Thanks, but I don't think that works... Response.OutputStream.Write doesn't take a Stream parameter (not in ASP.NET 2.0 anyway), only a byte array, which would require the file to be loaded into memory first, and therefore not really better than the WriteFile solution. – Mun Mar 03 '09 at 22:39
  • 2
    Regarding the byte array -- you don't have to load the entire stream into memory. The code I have uses at most 64kb of memory (plus minor overhead) during streaming. – Randolpho Mar 03 '09 at 22:42
  • How to assign stream response to HTML Video control? – Faizan Mubasher Oct 27 '14 at 07:16
3

After trying lots of different combinations, including the code posted in the various answers, it seems like setting Response.Buffer = true before calling TransmitFile did the trick and the web application is now a lot more responsive in Internet Explorer.

In this particular case, the SWF extension is also mapped to ASP.NET, and we're using a custom handler in our web application to read the files from disk and then send them to the browser using Response.TransmitFile(). We've got a flash-based video player to play video files which are also SWF's, and I think having all of this activity go through the handler without buffering is what may have been causing strange things to happen in IE.

Mun
  • 14,098
  • 11
  • 59
  • 83