WebAPI 2 Controllers (MVC Framework)

Web APIs are a way to use controllers to return raw data instead of html. Even thought is possible to return JSon from a normal controller’s action, a Web Api allow us a more data oriented environment, with many features which allow us a more powerful approach on that direction.

To add a new Web API Controller to an existent MVC Web Application (is possible as well to add a dedicated Web API project to our solution) we can right-click on our Controllers folder (or on the folter we want to use for our Web API controllers) and the select Add -> Controller. From the Controller selection form we can choose to add a new “Web API 2 Controller Empty”.

Doing this some new references and files will be added to the solution, to allow us to work with Web APIs. In particular we will have a new WebApiConfig.cs file, that is for the WebAPIs what something similar at what the RouteConfig.cs is for the normal controllers. Here is how it looks like:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
 
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

To be sure that everything works we have to ensure that the Register() method is effectively called in the Global.asax file. It’s important that the method is called just after the RegisterAllAreas() method, otherwise we can have some issue with the routing configuration. Here is a example of how the Global.asax should look like:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

As we can see we have a call to the MapHttpAttributeRoutes() method, to have automatically enabled the route attributes (as the MapMvcAttibuteRoutes() method does for the normal controllers). The we have the default routing configuration for our Web API controllers. Even though a configuration is provided is highly recommended, especially when parameters are provided, to use the route attributes to specify every route.

Differently from the normal controllers, which can return JSon data by returning the result of the Json() method as action, in this case we are just returning the object with the result of our method. Here is an example:

[Route("api/forumApi/getIntListWithCount/{count}")]
public List<int> GetIntListWithCount(int count)
{
    var list = new List<int>();
    for (var n = 0; n < count; n++)
    {
        list.Add(n);
    }
    return list;
}

Managing the output format

If we try to invoke our Web API we’ll discover that probably our list will be returned in XML format. It should be better to have it on JSon format. In reality things are a little more complicated: Web APIs implements a negotiation mechanism which return the result object in different formats based on the request. Indeed we can invoke our method from the client side to have the result as JSon or as XML:

<script>
    $.ajax({
        dataType: "json",
        url: "/api/forumApi/getIntListWithCount/20",
        success: function (data) {
 
            //Data as JSon
            debugger;
        }
    });
    $.ajax({
        dataType: "xml",
        url: "/api/forumApi/getIntListWithCount/20",
        success: function (data) {
 
            //Data as XML
            debugger;
        }
    });
</script>

So the reason why, if we try to directly refer our Web API method from the browser, we’ll probably get the result with XML format, is because many browsers add the XML content format by default when asking for an html page (and of course the browser is asking for an html page by default). So how can we fix this? Fortunately we just have to add some extra configuration to our WebApiConfig.cs file:

public static void Register(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
 
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
 
    //We set JSon as default format for any text/html request
    config.Formatters.JsonFormatter.SupportedMediaTypes.Add(
        new MediaTypeHeaderValue("text/html"));
 
    //We configure a way to force the output format by adding ?type=json to
    //force the json format and by adding ?type=xml to force the XML format
    config.Formatters.JsonFormatter.MediaTypeMappings.Add(
        new QueryStringMapping("type", "json", new MediaTypeHeaderValue("application/json")));
    config.Formatters.XmlFormatter.MediaTypeMappings.Add(
        new QueryStringMapping("type", "xml", new MediaTypeHeaderValue("application/xml")));
}

Leave a comment