Monthly Archives: June 2015

Attribute Routing in ASP.NET MVC

With earlier version of ASP.NET MVC routing was strictly convention based and there was no way to give custom routes for specific controller and action associated with it. With ASP.NET MVC 5 and above attribute based routing feature was introduced. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web application. The earlier style of routing, called convention-based routing, is still supported and you can combine both techniques in the same controller and web application as well. To enable attribute routing, call MapMvcAttributeRoutes during configuration in RouteConfig.cs file

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapMvcAttributeRoutes();

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

Now in the controller as part of action we can declare custom routes for each and every action

public class HomeController : Controller
{
    [Route("Home/Test")]
    [Route("Home/Test1")]
    [Route("Home/Test2")]
    public ActionResult Index()
    {
        return View();
    }

    [Route("users/about")]
    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";
        return View();
    }

    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";
        return View();
    }
}

You can set a common prefix for an entire controller by using the [RoutePrefix] attribute like show below

[RoutePrefix("Orders")]
public class HomeController : Controller
{
    [Route("Home/Test")]
    [Route("Home/Test1")]
    [Route("Home/Test2")]
    public ActionResult Index()
    {
        return View();
    }

    [Route("users/about")]
    public ActionResult About()
    {
        ViewBag.Message = "Your application description page.";
        return View();
    }

    public ActionResult Contact()
    {
        ViewBag.Message = "Your contact page.";
        return View();
    }
}

When to use Attribute Routing
The convention-based routing is complex to support certain URI patterns that are common in RESTful APIs. But by using attribute routing you can define these URI patterns very easily. For example, resources often contain child resources like Clients have orders, movies have actors, books have authors and so on. It’s natural to create URIs that reflects these relations like as: /clients/1/orders. This type of URI is difficult to create using convention-based routing. Although it can be done, the results don’t scale well if you have many controllers or resource types. With attribute routing, it’s pretty much easy to define a route for this URI.

Similar attribute routing concept holds good for Web API 2

Explain Model Binding in ASP.NET MVC ?

Suppose you had an API like shown below

public class Person
{
    public string FirstName { get; set; }
    public string Lastname { get; set; }
    public string Email { get; set; }
    public int Id { get; set; }
}
public class PersonController : Controller
{
    [HttpPost]
    public ActionResult Update(Person person)
    { 
        //Do Some thing over here
    }
}

You can easily post a Person to that action method using JSON through $ajax using jQuery. But the bigger question is how ASP.NET MVC transforms the JSON payload or forms payload to required object. Under the hood, ASP.NET MVC uses the DefaultModelBinder in combination with the JsonValueProviderFactory to bind that value.Then question arises Why simply deserialize the incoming JSON request directly to the model (Person)? There are couple of ways in which data gets posted

    • application/x-www-form-urlencoded – When you submit a typical HTML form, the content type of that submission is application/x-www-form-url-encoded. the contents of the form is posted as a set of name value pairs separated by ampersand characters. The name and value within each pair are separated by an equals sign. When content is posted in this format, the DefaultModelBinder calls into the FormValueProvider asking for a value for each property of the model
    • application/json – Another content type in which u can post data is through JSON objects like shown below
      <script type="text/javascript">
          $(function () {
              var person = { FirstName: "Aamol", LastName: "Gote", Email: "a@gmail.com", Id: 1 }
              var personJSON = JSON.stringify(person);
              $.ajax({
                  url: '/Person/update',
                  type: 'POST',
                  dataType: 'json',
                  data: personJSON,
                  contentType: "application/json",
              });
          });
      </script>
      

      When this code executes, notice that the content is encoded as JSON rather than form url encoded. JSON is a serialization format so it’s in theory possible that we could straight deserialize that post to a Person instance, but ASP.NET MVC does not do that, reason for it is has to perform validation on input values, if it does not then the serialization would fail. Serialization is an all or nothing affair, when serialization fails, all you know is that the format didn’t match the type. You don’t have access to the granular details we need to provide property level validation.

So to solve this we really want is a way bind each property of the model one at a time so we can determine which of the fields are valid and which ones are in error. Fortunately, the DefaultModelBinder already knows how to do that when working with the dictionary-like IValueProvider interface. All the ket value pairs form-encoded and JSON are coverted to type IValueProvider (Dictionary) and DefaultModelBinder already knows how to bind those values to a type while providing property level validation.
Value providers provide an abstraction over where values actually come from. Value providers are responsible for aggregating the values that are part of the current request, e.g. from Form collection, the query string, JSON, etc. They basically say “I don’t know what a ‘FirstName’ is for or what you can do with it, but if you ask me for a ‘FirstName’ I can give you what I have.”
Model binders are responsible for querying the value providers and building up objects based on those results. They basically say “I don’t know where directly to find a ‘FirstName’, ‘LastName’, or ‘Age’, but if the value provider is willing to give them to me then I can create a Person object from them.”

Model binders aren’t locked to individual sources they can build objects from an aggregate of sources for e.g. if you person object is posted and a client makes a JSON POST request to an action method with the url /person/update/1 with the following content:

{ FirstName: "Aamol", LastName: "Gote", Email: "a@gmail.com"}

The DefaultModelBinder will pull the Id value from the RouteData and the FirstName, LastName and Email values from the JSON when building up the Person object. Afterwards, it’ll perform validation without having to know that the various values came from different sources.
In Summary – we use a value provider for JSON to enable property level validation of the incoming post and also so that model binding can build up an object by aggregating multiple sources of data without having to know anything about those sources.