Play Videos in ASP.NET MVC & HTML5 using Custom ActionResult

Although the built-in result classes are sufficient for most application scenarios in ASP.NET MVC, it’s worth noting that one of the most important features in ASP.NET MVC is that a developer can extend this framework for occasions where your application requires something special. For eg: the Custom View Engine, Custom Controller Factory, Custom Action Result, Custom Action Filter can be used to extend ASP.NET MVC for your application requirements. This makes MVC as the most adaptive technology for web application development today.

Playing Video files in ASP.NET MVC

One such requirement in a web application could be that it allows binary contents e.g. images, videos, pdf etc. to be downloaded. ASP.NET MVC facilitates this requirement via the ActionResult abstract class. The derived classes from the ActionResult such as the FileContentResult and FileSTreamResult classes are useful to perform binary file download operations. However now consider the scenario that you as a developer want to restrict the Action method to download only the video file and sometimes instead of downloading it physically on the disk, just play it directly. Now that’s a special requirement, so how do we implement it in MVC? Enter the Custom Action Result which gets the job done!


Note: The example is just a demo to show the implementation of Custom ActionResult feature in MVC. Downloading Video or playing Video directly in a browser can be possible using various other methods in Web Applications.

Step 1: Open VS 2012 and create an ASP.NET MVC Empty application. Name it as ‘MVC40_CustomActionResult’. In this project, add a new folder and name it as ‘VideoFile’. In this folder, add Video files as per your choice. (I have used the .mp4 format)

Step 2: In the project, add a new folder name it as ‘CustomResult’. In this folder add a new class file and name it as ‘VideoResult.cs’. Add the following code in it:

using System.IO;
using System.Web.Hosting;
using System.Web.Mvc;


namespace MVC40_CustomActionResult.CustomResult
{
    public class VideoResult : ActionResult
    {
        /// <summary>
        /// The below method will respond with the Video file
        /// </summary>
        /// <param name="context"></param>
        public override void ExecuteResult(ControllerContext context)
        {
            //The File Path
            var videoFilePath = HostingEnvironment.MapPath("~/VideoFile/Win8.mp4");
            //The header information
            context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=Win8.mp4");
            

            var file = new FileInfo(videoFilePath);
            //Check the file exist,  it will be written into the response
            if (file.Exists)
            {
                var stream = file.OpenRead();
                var bytesinfile = new byte[stream.Length];
                stream.Read(bytesinfile, 0, (int)file.Length);
                context.HttpContext.Response.BinaryWrite(bytesinfile);
            }
        }
    }
}

The ExecuteResult method implementation above looks for the Video file. If it is found, then set the response by writing the file into the response.

Step 3: In the application, add a new MVC Empty Controller, name it as VideoController and implement the code as below:

using MVC40_CustomActionResult.CustomResult;
using System.Web.Mvc;


namespace MVC40_CustomActionResult.Controllers
{
    public class VideoController : Controller
    {
        //
        // GET: /Video/

        public ActionResult Index()
        {
            return new VideoResult();
        }

    }
}


The Index method now returns the VideoResult; the custom action result implemented in the previous step.

Step 4: Run the application and navigate to the, Video/Index URL and the download experience will be similar to the following:
video-download-mvc

Step 5: In the project, add a new MVC Empty controller with the name SampleController, and add an index method in it as shown below:

public class SampleController : Controller
{
//
// GET: /Sample/

public ActionResult Index()
{
    return View();
}

}

Step 6: Add a new View from the above action method, and add the following HTML 5 Video tag in it:

<video width="320" height="240" controls autoplay="autoplay">
  <source src="@Url.Action("Index","Video")" type="video/mp4">
</video>


The video tag shown above is provided in HTML 5. The src property is set to the Index method in the Video controller which we have implemented in Step 3.

Step 6: Run the application in a Browser (I have used Chrome), and the result will be as below:

mvc-html5-play-video
That’s it. So now you can have your ASP.NET MVC application ready for playing various videos in the browser.

This is a handy page that shows which browser supports HTML5 Video and in which video format.

Conclusion: In ASP.NET MVC, using its extensibility feature, a developer can implement domain based requirements to provide the best end-user experiences. Custom ActionResult is one of the mechanism using which developer can think of defining some restrictions on the responses delivered to the Browser.

10 comments:

  1. Awesome, you made my day!! I needed to stream a video from a file that is somewhere on the harddisk and not below inetpub. Yyour solution made it possible, THANKS!

    ReplyDelete
  2. This method won't work with non html5 compatible videos (html5 only supports ogg, mp4 and webm formats (see this link)

    Do you know how to play videos in other formats, like wmv or avi?
    I'm trying to get a behavior similar to accessing directly to the video url (http://localhost/video.avi). This method opens VLC media player plugin to play de video, instead of download it.

    ReplyDelete
  3. Rectify, using the correct MIME type for each format when serving the video, vlc plugin launches, but the video doesn't play.

    You can see the Correct MIME types here: http://www.encoding.com/correct_mime_types_for_serving_video_files

    I keep searching for the mistake.

    ReplyDelete
  4. I've found the solution!

    VLC plugin wasn't playing the video because it hadn't Authorization to execute the method (the web browser can access because user is logged in, but vlc player has not credentials).

    The trick is mark the method to allow anonymous access via "[AllowAnonymousAttribute]".

    ReplyDelete
  5. The above solution doesn't provide full support for HTML5 video (for example dynamic seeking or prefetching) as it requires support for Range Requests on the server side. You can read more on how to provide such support in ActionResult here: http://tpeczek.blogspot.co.uk/2011/10/range-requests-in-aspnet-mvc.html

    ReplyDelete
  6. Hi, can you help me, its work perfectly on ie, safari, firefox but not on a ipad..

    ReplyDelete
  7. Thank you for the article. It's strange, I've repeated all the steps you described, and I can download stream as a file, as described on Step 4, but the video player itself doesn't play the stream, says, Incorrect source. Maybe someone had already faced the same issue. What could be the problem? I can't think of any logical reason.

    ReplyDelete
  8. Hi There. You have set a static path of the file. But how to set a dynamic path.

    ReplyDelete