Web API Notes

Web page by Kevin Harris of Homer IL

Please contact Kevin Harris of Homer IL concerning this web site

Web API Notes


Web API is ASP.NET's framework for building HTTP based services. It was released with MVC 4 (.NET 4.0), but is not linked with MVC. It can be used with Web Forms, or any type of ASP.NET application, as well as MVC. The structure of Web API is similar to MVC; for example the routing design is the same. WCF 2.0 (.NET 3.5) contained support for HTTP services, but it was limited and tied to the WCF style of construction. Web API has a more flexible routing engine (similar to MVC) than WCF. Web API is a lightweight, extensible framework designed solely for creating HTTP services, where as WCF is a heavyweight framework supporting a number of different protocols. WCF also uses the XML-based SOAP format for messages while Web API can use the less verbose JSON format.

HTTP services (i.e. RESTful services) are the easiest type of service to build that can be accessed by the most number of clients. Since they are lightweight and use HTTP, they work well with clients which do not have a lot of processing power (e.g. mobile devices). Most modern clients have support for HTTP for Internet access. The degree to which Web API services meet the architectural style of being RESTful service depends upon the degree to which the services implement the tenants of REST as originally defined by Roy Fielding.

Web API provides automatic support for content negotiation which is a mechanism defined in the HTTP specification which makes it possible to serve data in different formats from the same URI. With content negotiation a client communicates with the server to get the data in a format which it can handle, or which it prefers. For example, content negotiation might allow a URI to return either a .gif or a .png image, or an payload in either XML or JSON, or page text in either German or English.

The specifications for content negotiation are given in IETF RFC 7231 3.4 Content Negotiation. The specification defines two patterns for content negotiation:

  1. Proactive - the server selects the representation (data format) based upon the user agent's (clients) stated preferences.

  2. Reactive - the server provides list of representations for the user agent to choose from.

These two patterns are not mutually exclusive and each has trade-offs in applicability and practicality. In Proactive content negotiation, the client sends an Accept header using a Quality value (q notation) to specify its preferences. The q values range from 1.000 (most preferred) to 0.000 (least preferred). Note a variant with a q value of 0.000 will never be chosen. Variants with no q values are given a default q value of 1.000. An example of a complex request is:

Accept-Language: fr; q=1.0, en; q=0.5
Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1


Accept headers can also include wildcard media types where "*" matches any string. For example:

Accept: image/*, */*


would indicate any type starting with "image/" is acceptable. The wildcard "*/*" is given a low preference of 0.01.

The servers send back the appropriate response with a Content-Type header. The client also sends a Content-Type header when sending a body (e.g. POST).

While Web API provides automatic support for content negotiation for all the major media types, it also provides the MediaTypeFormatter abstract class for instances where the media type is not one of the automatically handled types, or the media type is passed in outside of the Accept header, such as through a query string. MediaTypeFormatter enable a conversion of HTTP data to/from .NET types. Media type formatters are global formatters sitting in the Formatters property of HttpConfiguration. If you are using ASP.NET hosting (IIS, IIS Express, Cassini, etc.) then you may use GlobalConfiguration.Configuration to access the instance of HttpConfiguration containing Formatters. If you are using Self-Hosting, then you would be creating a HttpSelfHostConfiguration object which you will use its Formatters property.

Media Types

Media Types (aka MIME type, content type) are two-part identifiers for data contents transmitted of the Internet. The Internet Assigned Numbers Authority (IANA), a department of the Internet Corporation for Assigned Names and Numbers (ICANN), is the official authority for the standardization and publication of Media Types (formerly known as MIME types). See IANA - Media Types.

A media type is composed of a type, a subtype, and optional parameters. For example, an HTML file might be designated:

 text/html; charset=UTF-8


where "text" is the type, "html" is the subtype, and "charset=UTF-8" is an optional parameter indicating the character encoding.

There are 8 types:

  • application
  • audio
  • image
  • message
  • model
  • multipart
  • text
  • video

The subtypes can be divided into:

  • a standard subtype
  • a vendor specific subtype (indicated by "vnd")
  • an experimental or unofficial subtype (indicated by "x")

As well as being used in content negotiation (The Accept header), Media Types are specified in the Content-Type header to indicate the format of the data in the response or request (in the case of POST or PUT requests) body. So Media Types are used accordingly:

  • Accept Header - what the browser is able to understand.
  • Content Type Header - format of the data in the body.

Routing

Routing is the most common way to map URIs and HTTP verbs to the controller methods. Routing in Web API is similar to the routing in MVC, except different components are used to keep the Web API routing different from MVC routing. This is especially helpful when both MVC and Web API are used in the same project. Web API uses a different extension method than MVC for routing (MapHttpRoute) and uses a different route collection to keep the Web API and MVC routes separate. The default Web API route includes a "/api/" subdirectory to also keep the route mapping separate from the MVC routes. The Web API controller must derive from the APIController abstract class.

The MVC routes are defined in \App_Start\RouteConfig.cs while the Web API routes are defined in \App_Start\WebApiConfig.cs.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using System.Web.Mvc;
using System.Web.Routing;

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

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

RouteConfig.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
using System.Web.Http;

namespace KevinWebApiTemplateModified
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

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

WebApiConfig.cs

Note the difference between the MVC route and the Web API route above. The Web API does not use the {action} parameter in the route as does MVC. Instead of calling the action method by name, Web API associates the action methods with the HTTP verbs used in the Request.

Assemblies

Visual Studio 2015 includes the Web API assemblies into the project when the Web API check box is selected on the template page during project creation. However older versions of Visual Studio may require you to add Web-API to a project using the NuGet package manager. The assemblies included in a project are listed in the References branch of the TreeView in the Solution Explorer. The major Web API 2.0 assembles include:

  • System.Net.Http - Client and raw messaging types.
  • System.Net.Http.Formatting - Model binding and media type formatters.
  • System.Web.Http - Basic hosting infrastructure.
  • System.Web.Http.Common - Common APIs.
  • System.Web.Http.WebHost - ASP.NET hosting.
  • System.Web.Http.SelfHost- Self Hosting.
  • System.Web.Http.Data - DataController is an APIController that handles the "CRUD" type operations.
  • System.Web.Http.Data.EntityFramework - Specific implementations of DataController.
  • System.Web.Http.Data.Helpers - Common code for data api.

Convention and Configuration

In Web API the HTTP verbs are mapped to the controller methods by convention when the name of the methods are Get, Post, Put, or Delete. If different method names are used, they need to be mapped to the corresponding HTTP verbs with annotation attributes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
        //// GET api/values
        //public IEnumerable<string> Get()
        //{
        //    return data;
        //}

        // MyGet api/values
        [HttpGet]
        public IEnumerable<string> MyGet()
        {
            return data;
        }

Mapping Controller Methods to HTTP Verbs with Annotations

Model Binding, Media Type Formatters, and HTTP Messages

The .NET framework provides Model Binding which is the conversion of incoming messages to .NET data types. This is provided in the various types of .NET applications (WCF, MVC, Web API, etc). For example the framework converts the incoming XML or JSON into .NET types so the programmer does not have to deal with the lower level handling of stream data. Web API is similar to MVC model binding, but goes further by providing MediaTypeFormatters to specify content types when binding both input and output data. This could allow the application to accept incoming data in either XML or JSON.

If you need to go down to a lower level to work with messages directly, the HttpRequestMessage and HttpResponseMessage classes can be used. These classes allow you to go further down the HTTP stack to directly set values such as headers and response messages. For example, the Get code below uses HttpResponseMessage to return a 404 code with the text "Item not found" when a requested value is not found. Also the Post code returns a 201 code (Created) along with a Location header which specifies the location of the newly created item.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
   // GET api/values/5
        public HttpResponseMessage Get(int id)
        {
            if (data.Count > id)
            {
                return Request.CreateResponse<string>(HttpStatusCode.OK, data[id]);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Item not found");
            }
        }

        // POST api/values
        public HttpResponseMessage Post([FromBody]string value)
        {
            data.Add(value);
            var msg = Request.CreateResponse(HttpStatusCode.Created);
            msg.Headers.Location = new Uri(Request.RequestUri + "/" + (data.Count-1).ToString());
            return msg;
        }

Using HttpResponseMessage to Create Response Messages

Example WebAPI Project

Using Visual Studio 2015 Professional, create a new project, ASP.NET Web Application. To keep it simple as possible, I removed the following options: Add Application Insights to project, Host in the cloud, Add unit tests, and also changed the authentication to none. I selected the ASP.NET 4.5.2 Web API template (MVC and Web API options selected automatically).

.Default Web API Project

Web API Project using WebAPI Project Template

Below is a screen capture from running the project. The four windows, from outer to inner, are Internet Explorer running the Web API on local host via Visual Studio. Visual Studio 2015 showing the Values controller with the default Get() method (by convention, since no method is decorated with a [Get] attribute). Then Chrome calling the Web API service on local host and showing the returned results. And the inner most window is Chrome Developer Tools (F12) showing the network traffic for the Web API response.

.Running Default WebAPI

Running Default WebAPI


References



Error | ASP.NET Developer

Error

Error message

  • Warning: Cannot modify header information - headers already sent by (output started at /srv/disk9/1218369/www/kcshadow.net/aspnet/includes/common.inc:2748) in drupal_send_headers() (line 1232 of /srv/disk9/1218369/www/kcshadow.net/aspnet/includes/bootstrap.inc).
  • PDOException: SQLSTATE[42000]: Syntax error or access violation: 1142 INSERT command denied to user '1218369_b2cf'@'185.176.40.58' for table 'watchdog': INSERT INTO {watchdog} (uid, type, message, variables, severity, link, location, referer, hostname, timestamp) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5, :db_insert_placeholder_6, :db_insert_placeholder_7, :db_insert_placeholder_8, :db_insert_placeholder_9); Array ( [:db_insert_placeholder_0] => 0 [:db_insert_placeholder_1] => cron [:db_insert_placeholder_2] => Attempting to re-run cron while it is already running. [:db_insert_placeholder_3] => a:0:{} [:db_insert_placeholder_4] => 4 [:db_insert_placeholder_5] => [:db_insert_placeholder_6] => http://www.kcshadow.net/aspnet/?q=webapinotes [:db_insert_placeholder_7] => [:db_insert_placeholder_8] => 54.162.171.242 [:db_insert_placeholder_9] => 1534728088 ) in dblog_watchdog() (line 160 of /srv/disk9/1218369/www/kcshadow.net/aspnet/modules/dblog/dblog.module).
The website encountered an unexpected error. Please try again later.