Like many others, I have a huge pile of legacy apps that I maintain that are running very smooth with no justification for a major upgrade/update, lots of small code tweaks and simple enhancements, but nothing major. I had a new request the other day to add a basic warehouse tracking system that people could add packages too by scanning bar codes. Very simple process and something I could easily do with jQuery, jQuery tmpl plugin, and a back-end service. Before running off to build a WCF service, I decided to take a peek at Web API (version 2.1 included with Visual Studio 2013) to learn something new.

The MSDN tutorials were pretty straight forward but missing a few step, that I didn’t figure out till I messed things up a few times. Nothing terrible, and with GIT you can just toss the changes and start over again. ;)

Here is the play-by-play to add Web API 2.1 to Web Forms Application

  1. In the root of your Web Forms application create a folder called “api“.

    ** The name and location of this folder is best practice for Web API controllers.

     

  2. Right click on your new “api” folder and choose Add -> New Item from the right context menu.

    On the “Add New Item” menu, go to Web and choose Web API Controller Class (v2.1) and name your controller [Something]Controller.cs.

    ** The standard naming convention for Web API is to put the Suffix “Controller” on your Web API name. The world “Controller” will never be used in api calls, but it’s important for the convention based routing. In the example below, I created a Web API for my Inventory functions, I gave it a name of “InventoryController.cs”.

     

    using System.Collections.Generic;
    using System.Web.Http;
    
    namespace  ZachHunter.DemoProject.api
    {
        public class InventoryController : ApiController
        {
            // GET api/<controller>
            public IEnumerable<string> Get()
            {
                return new string[] { "value1", "value2" };
            }
    
            // GET api/<controller>/5
            public string Get(int id)
            {
                return "value";
            }
    
            // POST api/<controller>
            public void Post([FromBody]string value)
            {
            }
    
            // PUT api/<controller>/5
            public void Put(int id, [FromBody]string value)
            {
            }
    
            // DELETE api/<controller>/5
            public void Delete(int id)
            {
            }
        }
    }
    

     

  3. Next go to your “App_Start” folder in the root of your application (if you don’t have this folder, create it) and right click on the folder to add a new class named “WebApiConfig.cs”.

    ** This is recommended location to store your Web API routing configuration.

    Add the following two routing rules into your WebApiConfig.cs file to enable convention and attribute based routing

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http;
    
    namespace ZachHunter.DemoProject
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Attribute Routing
                // Allows for custom routing to be set at the method, example [Route("api/warehouse/scheduling/all")]
                config.MapHttpAttributeRoutes();
    
                // Convention-Based Routing
                // Allows for standard controller based routing, example api/warehouse, api/warehouse/1
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
            }
        }
    }
    

     

  4. Finally, open your Global.asax.cs and add modify your Application_Start to load your Web API routing configuration.

     

            protected void Application_Start(Object sender, EventArgs e)
            {
                // Here are settings to change the default JSON.net Json formatting to indented, many other options to choose.
                HttpConfiguration config = GlobalConfiguration.Configuration;
                config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
    
                // WebApi Routing, loads up your Web API routes stored in App_Start/WebApiConfig.cs
                GlobalConfiguration.Configure(WebApiConfig.Register);
            }
    

Automatic changes made when you added Web API 2.1 Class

References:

Newtonsoft.Json.dll
System.Net.Http.dll
System.Web.Http.WebHost.dll

Web.Config

    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  ...
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

When your all done, you can browse to the api url by running your project and typing in the convention base syntax listed in the comments above the auto generated method (e.g. api/inventory). If you use IE, it will default to loading JSON or you can use FireFox and it will default to XML.

Her is a basic call in jQuery using the Web API sample above

$(document).ready(function () {

            $.ajax({
                type: 'GET',
                url: '/api/inventory,
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                data: '',
                success: function (results) {
                    // Do Something with the Results
                },
                error: function (xhr, textStatus, error) {
                    // In case of ERROR, do something else
                }
            });
});