Delivering solid user friendly software solutions since the dawn of time.

Introduction to the ASP.Net WebApi - Notes

Categories: Notes WebApi

Introduction to the ASP.NET WebApi
Jon Flanders

  • Service layer for HTML5, mobile applications, ...
  • REST : Representational State Transfer (Roy Fielding)
  • Full rest -> Level4 service
new { id = RouteParameter.Optional }
public string Get() //returns all
  return this.Request.GetUserPrinciple().Identity.Name;
public HttpResponseMessage<Instructor> Get(int id)
   var instructor = (from ...)
   if (null == instructor)
      //return 404
      var notfoundMessage = new HttpRequestMessage<Instructor>(HttpStatusCode.NotFound);
      return notfoundMessage;       
   var newMessage = new HttpRequestMessage<Instructor>(instructor);
   return newMessage;
public HttpResponseMessage<Instructor> Post(Instructor instructor)
   //create and insert and return 201 
   var newMessage = new HttpRequestMessage<Instructor>(instructor, HttpStatusCode.created);
   newMessage.Headers.Location = 
      new Uri(Request.RequestUri, "/instructors/" + instructor.ID.ToString());
public Instructor Put(Instructor instructor)
{ update }
public Instructor Delete(int id)
{ remove }
  • ModelBinder for Body, header, querystring
  • MediaTypeFormatters
  • Validation via attributes
  • HttpRequestMessage and HttpResponseMessage
  • Content negotiation (xml or json)
  • Customize file extension or querystring
  • Fidler : Post with Content-Type:application/json
  • http://odata.org with IQueryable
  • HttpConfiguration class
  • GlobalConfiguration.Configuration
  • DependencyResolver 
Uniform interface of REST
  • Start with URI, add well-known HTTP verbs
  • Get: cacheble, safe, always same effect (idempotent)
  • Post: create new resource, unsafe, non-cached 
  • Put: update, idempotent
  • Delete: remove, idempotent
  • You can specify multiple verbs to one method
ApiController: IHttpController, IDisposable
   Configuration, ControllerContext, ModelState, Request, Url, Task<HttpResponseMessage>, ExecuteAsync, Initialize
  Content, Headers, Method, Properties, RequestUri, Version, Displose
  Content, Headers, IsSuccessStatusCode, ReasonPhrase, RequestMesage, StatusCode, Version, Dispose, EnsureSuccessStatusCode
url: '/api/foo/id',
success: function (data) {},
statusCode: { 
404: function() {} 
  • HttpWebRequest, WebClient
var c = new HttpClient();
c.GetAsync(uri).ContinueWith((t) =>
  HttpResponseMessage response = null;
  response = t.Result;
  response.Content.ReadAsAsync<JsonObject>().ContinueWith(readTask) =>
  • http://search.twitter.com/search.json?q=fun
  • PostAsync, PutAsync
  • ObjectContent<T> for Json or XML
  • StreamContent for raw data
  • MultipartContent and MultiPartFormContent
  • ByteArrayContent, FormUrlEncodedContent, StringContent
  • UploadVideoClient (HttpClient)
  • Dealing with headers
  • Dealing with cookies 
Per-request headers
var pcontent = new HttpRequestMessage<Person>().CreateContent<Person>(new Person());
pcontent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
  • public class HttpClientHandler : HttpMessageHandler
  • Derive from DelegatingHandler
  • The HttpClient does not send a UserAgent by default
  • client.DefaultRequestHeaders.Add("User-Agent","Jon's Cool Client");
  • Token-based authorization can be accomplished by a custom HttpClientHandler
Self-Hosting Example
  • Create a HttpConfiguration (eg. HttpSelfHostConfiguration)
  • Create your HttpServer (eg. HttpSelfHostServer)
  • Start listening: HttpServer.OpenAsync();
  • When using the first contructor overload, you end up with HttpControllerDispatcher as your HttpMessageHandler. It allows you to use the same ASP.NET routing and same convention or configuration settings as ApiController in ASP.Net Hosting.
  • config.Routes.MapHttpRoute("DefaultRoute", "{controller}/{id}", new { id=Parameter.Optional });
  • You can pass HttpServer to HttpClient, useful for self-hosting testing (all in memory)
var client = new HttpClient(server);
(t)=>{ var result = t.Result; result.Content.ReadAsStringAsync().ContinueWith(
(tr) => { Console.Write(rt.Result);})
ASP.NET Authentication or WCF for self-hosting
AllowAnonymousAttribute : explicitly allow access to action of apicontroller
Forms authentication
  • /account/jsonlogin endpoint with MVC4 projects
  • Authentication_JSON_AppService.axd
  • App gets cookie
Basic authentication
  • HttpClient/WebHttpRequest/WebClient understand Windows authentication
You can add support for token authentication (eg OAuth) fairly easily
  • AuthorizeAttribute with names or roles on individual actions (returns 401 if unauthorized)
  • HttpMessageHandler
  • request.GetUserPrincipal().Identity.Name;
  • HttpSelfHostConfiguration
protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
   httpBinding.Security.Mode = HttpBindingSecurity.TransportCredentials;
   return base.OnConfigureBinding(httpBinding);
Asp.Net Hosting
  • Global.asax.cs
  • GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
  • GlobalConfiguration.Configuration
  • HttpConfiguration
  • Filters, Formatters, MessageHandlers, Routes, ServiceResolver
  • IncludeErrorDetailPolicy.Always / Never / LocalOnly
Formatters will match incoming Content-Type with a MediaTypeFormatter (content negotiation and serialization)
  • JsonP
  • Inject code that isn't in same domain as controller
  • HttpResponseMessage<JsonPReturn> Get(int id, string callback)
  • response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/javascript");
function myCallback(obj) { document.getElementById('msg').innerText = obj.Data; }
<script src="http://server.com/api/controller/values/1?callback=myCallBack" />
Filters hook into the model binding and controller execution pipeline (model-related issues)
  • AuthorizeAttribute is an IFilter
  • MyFilter : IActionFilter
  • actionContext.ActionArguments 
Message Handlers are the http processing pipeline base class (http-issues)
  • HttpServer, HttpClientHandler, HttpControllerDispatcher
public class MyMethodOverrideHandler : DelegatingHandler
   const string header = "X-HTTP-Method-Override";
   //override SendAsync 
   //and let clients put the real verb in this header
ServiceResolver (internal implementation detail extensibility)
  • Implement IDependencyResolver or Call SetResolver and pass in two delegates
Action Filter vs. Mesage Handler
  • MessageHandler - before model binding - HTTP message level - eg. run an xml Schema validation
  • ActionFilter - after model binding - Extending your controller - eg. run an object validation