Quote for the Week

"Learn to enjoy every moment of your life"

Thursday, October 29, 2015

ASP.net MVC Model Binder

Model Binders is a powerful extension point to the ASP.NET MVC. It allows you to define your own class which is responsible for creating parameters for your controller actions. Scott Hansleman had a good example showing how to decouple a controller from HttpContext's user property.

Recently I've started a new Proof of Concept site which is based upon REST. My goal was to build a single web site which would expose its resources as addressable items. That is the URL defines the resource. This site should also be able to serve multiple clients which want different representations of the same resource.

For example assume we have an Automobile Parts catalog. We might have the browser point to http://myPartsCatalog.com/Ford/OilFilters/ which would render an HTML page of all the ford oil filters. Now let us say we want to implement an AJAX callback on the page so as a user mouse overs a specific part, the site might send a request to http://myPartsCatalog.com/Ford/OilFilters/fl1a, with the intention of gathering additional data about the part to display to the user. For this request we don't want to get an HTML representation of the part, we want the part rendered as JSON or XML, which will let us programatically access the part information.

I have grown tired of having to support multiple sites / pages one that renders the HTML and another that provides an API and exposes the data. The natural seperation of concerns that the MVC model gives us makes this an ideal platform to build a single web site which can serve HTML, XML, JSON or any other content we could imagine (for example what about a PDF version of the HTML page for offline usages).

To do this imagine we have the following controller defined:


public class PartController : Controller
{
public ActionResult List(string oem)
{
}
public ActionResult Detail(string oem, string partnumber)
{
}
}


We need a way to determine how the client wants the data to be returned. We could put that in the URL; however, that doesn't feel very restful. A key idea of a REST implementation is leveraging the capabilities in the HTTP protocol to define the resource your requesting. One of the Http Header's is Accept.

The Accept header allows us to define the content type that the client is requesting. So we could indicate in our request that we want text/json or text/xml. We could then put the following code in our controller:



        public ActionResult List(string oem)
        {
            //Get the Model for OEM.
            switch (HttpContext.Request.AcceptTypes[0])
            {
                case "*/*":
                case "text/html":
                    return View("PartList.aspx");
                case "text/json":
                    return View("PartList.json.aspx");
            }
        }


Warning: I am not finished investgating how ASP.Net handles the Accept header and my switch statement might not work; however, this is an example to highlight the flexibility of ASP.Net MVC.

So this works great; except that we want to unit test our code to ensure we are returning the right view for each request; however our controller is bound HttpContext which can be difficult to unit test. So the question is how do we decouple our controller from HttpContext? IModelBinder's are the answer.

We can define a ModelBinder by implementing the IModelBinder interface. The interface requires a single method that takes a couple parameters which provide context about the request, and returns an object.



    public class ContentTypeModelBinder : IModelBinder
    {

        #region IModelBinder Members

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (bindingContext == null)
            {
                throw new ArgumentNullException("bindingContext");
            }

            return controllerContext.HttpContext.Request.AcceptTypes[0];
        }

        #endregion
    }



The return value from the function will be used to pass in to a parameter in a controller. This allows us to change our controller definition to:

        public ActionResult List(string oem, [ModelBinder(typeof(ContentTypeModelBinder))]string contentType)
        {
            //Get the Model for OEM.
            switch (contentType)
            {
                case "*/*":
                case "text/html":
                    return View("PartList.aspx");
                case "text/json":
                    return View("PartList.json.aspx");
            }
        }


The magic here is the ModelBinder attribute which is applied to the contentType parameter. This tells the ASP.Net MVC runtime to use our own custom IModelBinder to provide the value for the contentType attribute. 



The thing I don't like about this is that we have to use an attribtue in our controller. It is possible to indicate that all instances of a specific type use a specific binder. But I will leave that for a different article.

Enjoy..!!

Tuesday, October 6, 2015

Asynchronously Vedio streaming using ASP.NET Web API

A lot of people think that ASP.NET Web API is basically a fancy framework for building APIs – which couldn’t be further from the truth. Web API is mainly about the new .NET HTTP programming model it brings to the table – embracing HTTP to perform a whole magnitude of web related tasks; and APIs are just a small portion of that. Hopefully if you follow this blog, you have seen examples of that already, as we often wander in the unkown areas of ASP.NET Web API, beyond building “traditional” APIs.

Today, let’s go back to the HTTP programming model and use Web API to asynchronously stream videos.

More after the jump.

The concept of asynchronous streaming

To perform the async streaming task, we will revert to the class we already previously used on this blog – and that is PushStreamContent. It allows the developer to progressively push packets of data down to the receiving client. Previously, we used PushStreamContent and JavaScript’s Server Sent Events to create an HTML5 chat.

In our new scenario, we will read the video stream from the file on the server’s hard drive, and flush it down to the client (using PushStreamContent) in the packets of 65 536 bytes. The streaming video playback could then start immediately (client doesn’t have to wait for the entire video to be flushed down), without causing unnecessary load on our server, especially as the process of writing to the client happens asynchronously. Once the client disconnects, the writing stops.

Implementation

PushStreamContent takes an Action in its constructor:


public PushStreamContent(Action<Stream, HttpContent, TransportContext> onStreamAvailable);

This Action is called as soon as the output stream (HTTP content to be flushed to the client) becomes available.

Therefore, we could create a small helper class, which would read the from the disk, and expose this activity for PushStreamContent to call repeatedly.

public class VideoStream
{
   private readonly string _filename;

   public VideoStream(string filename, string ext)
   {
      _filename = @"C:UsersFilipDownloads" + filename + "."+ext;
   }

   public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
   {
      try
      {
      var buffer = new byte[65536];

      using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
      {
         var length = (int)video.Length;
         var bytesRead = 1;

         while (length > 0 && bytesRead > 0)
         {
            bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
            await outputStream.WriteAsync(buffer, 0, bytesRead);
            length -= bytesRead;
         }
      }
      }
      catch (HttpException ex)
      {
         return;
      }
      finally
      {
         outputStream.Close();
      }
   }
}

This class is obviously little simplified, for the sake of demo purposes, but hopefully you get the idea. We allow the consumer of the class to give as information about the file (for which we arbitrarily look in a specific location, the Downloads folder in this case). In the WriteToStream method, we proceed to read the file progressively and flush these bits to the output stream.

Notice that the signature of this method matches the Action expected by PushStreamContent and as a result can be used by it.

Now let’s move to the controller action, which, by now, will be very simple (all the heavy lifting happens in the above VideoStream class).


public class VideosController : ApiController
{
   public HttpResponseMessage Get(string filename, string ext)
   {
      var video = new VideoStream(filename, ext);

      var response = Request.CreateResponse();
      response.Content = new PushStreamContent(video.WriteToStream, new MediaTypeHeaderValue("video/"+ext));

      return response;
   }
}

We allow the client to pass video info (name, extension), construct the instance of VideoStream and then create and instance of PushStreamContent which gets returned to the client.

All we need now is just a route registration:

config.Routes.MapHttpRoute(
    name: "DefaultVideo",
    routeTemplate: "api/{controller}/{ext}/{filename}"
);

Consuming the asynchronous video stream

In this case, I will be requesting this video: C:UsersFilipDownloadsCkY96QuiteBitterBeings.webm.

If we run this in the browser that supports WebM, we could see that the video (especially if you open the network inspection console) is streamed rather than loaded at once. To better illustrate this, I have recorded a short video which shows the application in action. I’ve put a breakpoint inside WriteToStream method, to show that subsequent packets of video get sent down *after* the playback has already started; the client can commence the playback already after the first 64kB packet. Also, as soon as the breakpoint hits, nothing more gets sent to the client, yet the browser still continues the playback of what it has already received. 

Summary
While there are arguably many better solution for video streaming (media protocols, media servers and so on), in my opinion, this type of functionality is a pretty nifty example of how flexible Web API can be in terms of working with HTTP programming – and how many different things it can do.

On a side, PushStreamContent itself is a very interesting class, and if used correctly, can be a very powerful weapon in the arsenal of Web API developer. A very interesting article about a similar topic (async with PushStreamContent) can be found here, by Andrés Vettor. Really worth a read!