Easy Handling of Http Range Requests in ASP.NET

I was recently working on adding video playing capabilities to a client’s existing ASP.NET application. They had video files that had been uploaded by users, and they wanted to allow the users to be able to preview the files on the web. I found MediaElement.js to be a excellent solution for this: As long as there were WEBM and H.264 encoded versions of the video to be played, it would handle playing the video on most browsers/devices and would fall back to a Flash video player if html video was not supported.

I did up a sample page, encoded some sample videos and everything worked great. However when I finally implemented it on the ASP.NET application only the Flash fallback player would play the videos. The HTML 5 player would not play the video.  I finally narrowed down the culprit to the way the video files were returned to the browser. Chrome and the iPhone/iPad require Http Range Requests to be supported for HTML5 video support.  Range requests allow the browser to only request a portion of the file from the server. So for videos, the user could drag the seek slider to the middle of the video and the browser would request the video from that point on, instead of downloading the full file from the server.

IIS 7 supports range requests natively, so if you are simply serving the video files directly from IIS you won’t have any problems. In this case, all file requests were being served by an ASPX page – it looked up information in a database as well as did some authorization checking before returning the file.  Unfortunately range requests are not natively supported from aspx responses – they have to be handled manually.

Scott Mitchell wrote a great article and HTTP Handler to handle this exact scenario, and it looks like a great solution. It’s very detailed and looks like it handles pretty much every edge case. Unfortunately it would require a lot of changes to fit into my client’s existing solution (and I didn’t want to rewrite the client’s solution – as it worked well for every other case), so I searched for a simpler solution.

After a lot of searching I finally found the VideoStreamer project at CodePlex by cipto0382. It includes a great little function that handles Http Range Requests.  I was able to include it in my project with very few modifications and it worked great. Chrome, Iphone and the IPad now played the video served by the ASP.Net Application.

I’ve included the function for reference below. It checks if the HTTP Request is a range request and returns a partial file with the necessary headers if it is. If it’s not a range request, it simply returns the complete file:

RangeDownload by cipto0382

private void RangeDownload(string fullpath,HttpContext context)
	long size,start,end,length,fp=0;
	using (StreamReader reader = new StreamReader(fullpath))

		size = reader.BaseStream.Length;
		start = 0;
		end = size - 1;
		length = size;
		// Now that we've gotten so far without errors we send the accept range header
		/* At the moment we only support single ranges.
		 * Multiple ranges requires some more work to ensure it works correctly
		 * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
		 * Multirange support annouces itself with:
		 * header('Accept-Ranges: bytes');
		 * Multirange content must be sent with multipart/byteranges mediatype,
		 * (mediatype = mimetype)
		 * as well as a boundry header to indicate the various chunks of data.
		context.Response.AddHeader("Accept-Ranges", "0-" + size);
		// header('Accept-Ranges: bytes');
		// multipart/byteranges
		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2

		if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
			long anotherStart = start;
			long anotherEnd = end;
			string[] arr_split = context.Request.ServerVariables["HTTP_RANGE"].Split(new char[] { Convert.ToChar("=") });
			string range = arr_split[1];

			// Make sure the client hasn't sent us a multibyte range
			if (range.IndexOf(",") > -1)
				// (?) Shoud this be issued here, or should the first
				// range be used? Or should the header be ignored and
				// we output the whole content?
				context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
				throw new HttpException(416, "Requested Range Not Satisfiable");


			// If the range starts with an '-' we start from the beginning
			// If not, we forward the file pointer
			// And make sure to get the end byte if spesified
			if (range.StartsWith("-"))
				// The n-number of the last bytes is requested
				anotherStart = size - Convert.ToInt64(range.Substring(1));
				arr_split = range.Split(new char[] { Convert.ToChar("-") });
				anotherStart = Convert.ToInt64(arr_split[0]);
				long temp = 0;
				anotherEnd = (arr_split.Length > 1 && Int64.TryParse(arr_split[1].ToString(), out temp)) ? Convert.ToInt64(arr_split[1]) : size;
			/* Check the range and make sure it's treated according to the specs.
			 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
			// End bytes can not be larger than $end.
			anotherEnd = (anotherEnd > end) ? end : anotherEnd;
			// Validate the requested range and return an error if it's not correct.
			if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)

				context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
				throw new HttpException(416, "Requested Range Not Satisfiable");
			start = anotherStart;
			end = anotherEnd;

			length = end - start + 1; // Calculate new content length
			fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
			context.Response.StatusCode = 206;
	// Notify the client the byte range we'll be outputting
	context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
	context.Response.AddHeader("Content-Length", length.ToString());
	// Start buffered download
	context.Response.WriteFile(fullpath, fp, length);


17 Responses to “Easy Handling of Http Range Requests in ASP.NET”

  1. Don Nell says:

    Thanks you (and Scott) for sharing this.

    I was stuck for almost 3 days in a similar situation having to support video content on both desktop and mobile devices. No issues on any browsers except the IOS devices. Found this article, implemented the function above unchanged and all is well.

    Thanks again.

  2. James Lovett says:

    Hi Chris, thank you for this brilliant post. And thanks to Scott too! This has had me banging my head against a brick wall for weeks!

  3. Thanks says:

    Thank you, this helped me immensly, very useful.

  4. Chris says:

    How do you handle large files. If I use this code on a file larger than int32 I get:

    “The size parameter must be between zero and the maximum Int32 value.
    Parameter name: size
    Actual value was 3413381708.”

    is there away to make it work with large video files?


    • I assume it’s the Response.WriteFile that’s causing the error? You’ll have to add some logic that says if the length is greater than Int32.MaxValue, then set the length to Int32.MaxValue and adjust the ‘end’ variable accordingly.

  5. Karthic says:

    Excellent article. Thanks for the code and references.

  6. Helge says:

    Thank you! Thank you! Thank you! Easy to implement and works right away. It took me 30 seconds! Thank you!

  7. Fredrik says:

    Thank you for sharing this! You saved me from hours of work, and also thanks for writing good, self-contained code that really worked out-of-the box! Thanks again!

  8. abhishek says:

    Hi there
    I am trying to add this handler in my visual studio 2013 solution with .Net 4.5.
    The solution works fantastic against large file upto 500 mb in visual studio 2008 but as soon as i move to VS2013 with latest .Net4.5. I get error:
    Not enough storage is available to process this command. (Exception from HRESULT: 0x80070008)

    I did registry fix mentioned by Microsoft , i added response.flush etc. It helps a bit as it played once or twice but then again fall back to that error.

    Code is replica on both VS2013 and VS2008, i even tried same .Net3.5 version and serving same 360Mb file. Works like a charm in Vs2008 but failed in Vs2013.

    Any help is appreciated

    • I can’t say i’ve run into this before. I am thinking though that maybe it doesn’t have to do with Visual Studio as much as what’s used to host your solution. Are you using the visual studio built in web server to test? I believe they’re different between VS 2008 and VS 2013 (2013 uses IIS Express).

      I would try hosting the app using full IIS to see if it works properly there.

      • abhishek says:

        actually its working on production environment :), sorry i was bit lazy to test it on that.

        btw IE does not do any range request for any file, either big or small, via http handler or even a direct hosted link of mp4 file. IT just tries to download the whole file first. Do you know why or can we change that behavior.

        I don’t want to web optimize my file using ffmpeg or something.

        • If this is for viewing online on the site itself, I suggest you use an html5 video player like http://mediaelementjs.com/. But you likely will have to use ffmpeg to convert the video, depending on it’s format. Alternatively, you could upload them to YouTube and use YouTube’s player on your site – assuming you want them available to the general public.

      • Abhishek Saxena says:

        Hi Chris
        thanks for bearing with me
        i think i found the way
        i did compared headers of all the initial requests done by chrome and IE when playing a file using direct link as well as our http handler.
        What i found is that : IE is not making range request proactively like chrome and firefox if served by http handler.
        our handler when does not detect “Range” in the request header coming from IE, it goes to else part of this function to process handler request, which in turn pushes the whole file out.
        I looked at header that plays a direct link to file in IE, it got this in it
        Then IE comes to know that it can do range request. So i added that header below in else part:

        if (!String.IsNullOrEmpty(context.Request.ServerVariables[“HTTP_RANGE”]))
        //request for chunk
        RangeDownload(fullpath, context);
        //ask for all
        long fileLength = File.OpenRead(fullpath).Length;
        context.Response.AddHeader(“Content-Length”, fileLength.ToString());
        context.Response.AddHeader(“Accept-Ranges”, “bytes”);

        and wohoo!! it starts playing in IE.

Leave a Response