To Document ASP.net REST APIs

Web API v2 has made ASP.net a great choice for building REST APIs, but great APIs need great documentation. In this post, we'll look at how to add auto-generated documentation seamlessly to our Web APIs. 

In the REST API world, there is something called the Swagger Project. A Swagger specification is a language-agnostic way to describe your REST API. In most popular web stacks, there are tools to generate and consume Swagger specs and .net is no exception. Enter Swashbuckle, an amazing open-source .net integration library for Swagger. Swashbuckle performs two main tasks:

  1. Automatically generate a swagger specification from your OWIN assemblies.
  2. Host a web page for displaying the documentation. 

Without further delay, let's dive into the code. Open Visual Studio and create a new Console Project. Ahh... that new project smell. Next, add two NuGet references from the Package Manager Console:

Install-Package Microsoft.Aspnet.WebAPI.OwinSelfHost
Install-Package Swashbuckle.Core

With these two packages installed, let's move on to define our OWIN entry point. Add a new class to the project called "Startup" (Startup.cs) and paste the following code:

using System.Collections.Generic;
using System.Net.Http.Formatting;
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Owin;
using Swashbuckle.Application;

namespace OwinSwagger
{
    public class Startup
    {
        public void Configuration( IAppBuilder app )
        {
            var config = new HttpConfiguration();

            //Use JSON friendly default settings
            var defaultSettings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                Converters = new List<JsonConverter>{ new StringEnumConverter{ CamelCaseText = true }, }
            };
            JsonConvert.DefaultSettings = () => { return defaultSettings; };

            //Specify JSON as the default media type
            config.Formatters.Clear();
            config.Formatters.Add( new JsonMediaTypeFormatter() );
            config.Formatters.JsonFormatter.SerializerSettings = defaultSettings;

            //Route all requests to the RootController by default
            config.Routes.MapHttpRoute( "api", "{controller}/{id}", defaults: new { id = RouteParameter.Optional } );
            config.MapHttpAttributeRoutes();

            //Tell swagger to generate documentation based on the XML doc file output from msbuild
            config.EnableSwagger( c =>
            {
                c.IncludeXmlComments( "docs.xml" );
                c.SingleApiVersion( "1.0", "Owin Swashbuckle Demo" );
            } ).EnableSwaggerUi();

            app.UseWebApi( config );
        }
    }
}

The names of the class (Startup), method (Configure), and parameters (IAppConfig) are all OWIN conventions and must be left intact for this example. Most of the code above is telling OWIN to use sensible defaults for returning human-readable JSON from the APIs. Toward the end of the function, EnableSwagger() tells Swashbuckle to ingest a file called "docs.xml" and serve up the comments within. Next, let's configure Visual Studio to generate "docs.xml". Right click your Console Application Project and click properties. Navigate to the "Build" tab and check "XML documentation file" at the bottom. Rename the file to "docs.xml" but leave the path intact. 

The XML documentation file contains all the /// comments throughout your visual studio project

Next we need to start the web service from Main() in program.cs. Here's the code:

using System;
using System.Diagnostics;
using Microsoft.Owin.Hosting;

namespace OwinSwagger
{
    class Program
    {
        static void Main( string[] args )
        {
            var url = "http://*:5000";
            var fullUrl = url.Replace( "*", "localhost" );
            using( WebApp.Start( fullUrl ) )
            {
                Console.WriteLine( "Service started at {0}", fullUrl );
                Console.WriteLine( "Press ENTER to stop." );
                LaunchDocumentation( fullUrl );
                Console.ReadLine();
            }
        }

        static void LaunchDocumentation( string url )
        {
            Process.Start( "chrome.exe", string.Format( "--incognito {0}", url + "/swagger/ui/index" ) );
        }
    }
}

When we run the app, it will launch chrome and navigate to http://localhost:5000/swagger/ui/index, which is the default location of the Swagger web page hosted by Swashbuckle. This gives the console application a nice CTRL+F5 experience. Finally, let's add a controller and a resource so we can see our generated documentation in action. Create a new class called BookController:

using System.Web.Http;
using System.Web.Http.Description;

namespace OwinSwagger
{
    /// <summary>
    /// Resource representing a book.
    /// </summary>
    public class Book
    {
        /// <summary>
        /// The self-link
        /// </summary>
        public string Href { get; set; }

        /// <summary>
        /// The name of the author
        /// </summary>
        public string Author { get; set; }

        /// <summary>
        /// The title of the book
        /// </summary>
        public string Title { get; set; }
    }

    public class BookController : ApiController
    {
        /// <summary>
        /// Retrieves a book with the specified Id.
        /// </summary>
        /// <param name="id">The id of the book to retrieve</param>
        [ResponseType( typeof( Book ) )]
        public IHttpActionResult Get( string id )
        {
            //a real controller would need to take the id and look up the book in the database
            //let's hack it below to always return a single book
            var book = new Book
            {
                Author = "Stephen King",
                Title = "Hearts in Atlantis",
                Href = Request.RequestUri.ToString(),
            };
            return Ok( book );
        }
    }
}

Start the project (CTRL + F5) and you should see the following:

This is a screenshot from IE, but our code in Main() should launch chrome instead. 

Notice all the XML comments on our Book and BookController are displayed in this handy little web page. It also shows the HTTP methods that are available, descriptions and names of parameters, and even includes a "Try it out!" button to call your API right from the documentation page. Clicking the "Try it out!" button is left as an exercise for the reader. 

The great thing is, all this documentation is generated automatically and will always be up-to-date as long as your keep your comments fresh. In future posts, I will describe how to use advanced REST clients like Postman to load up the swagger specification and create an entire API preset. 

Here's a link to this code on Github: https://github.com/robzhu/OwinSwagger

To Run ASP.net vNext on Docker

Microsoft recently announced that the future of .NET will be portable and open source. In addition to the monolithic .net Framework, .net Core will be released as individual packages on NuGet. Among other exciting possibilities, this means we can run ASP.net vNext inside a Docker Container. Unfortunately, as of 12/7/2014, this sample does not work unless we make a minor correction. 

Before we go over the solution, let's describe the error. First, we need to set up a CoreOS instance. Once CoreOS is up, SSH to it and follow the instructions. At the end, the docker container does not start correctly when runing "docker --tls run -d -t -p 8080:5000 myapp". To find out what happened, edit the second Dockerfile and remove the last line (ENTRYPOINT ["k", "web"]). Next, execute "docker run -it myapp". This opens an interactive session to the myapp container, from which we can run "k web" manually. Doing so yields the following exception:

System.InvalidOperationException: No service for type 'Microsoft.Framework.DependencyInjection.ServiceLookup.IServiceManifest' has been registered.
  at Microsoft.Framework.DependencyInjection.ServiceProviderExtensions.GetRequiredService (IServiceProvider provider, System.Type serviceType) [0x00000] in <filename unknown>:0
  at Microsoft.Framework.DependencyInjection.ServiceProviderExtensions.GetRequiredService[IServiceManifest] (IServiceProvider provider) [0x00000] in <filename unknown>:0
  at Microsoft.AspNet.Hosting.HostingServices.Import (IServiceProvider fallbackProvider) [0x00000] in <filename unknown>:0
  at Microsoft.AspNet.Hosting.HostingServices.Create (IServiceProvider fallbackServices, IConfiguration configuration) [0x00000] in <filename unknown>:0
  at Microsoft.AspNet.Hosting.Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0
root@10f8b18bf367:/app/src/helloworldweb#

As a temporary work around, we can use an older version of the KVM install script from the dev branch instead of the master branch. In the original instructions, within the first Dockerfile, replace the line

"RUN curl -s https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.sh | sh"

With 

"RUN curl -s https://raw.githubusercontent.com/aspnet/Home/dev/kvminstall.sh | sh"

Then the rest of the sample should work as intended. Please let me know in the comments if this workaround did the trick.

Note: "k web" runs the sample using the Nowin vNext server. This appears to be the only server that currently works on Linux (WebListener is unavailable on Linux and Kestrel has issues with Libuv). I have created a sample to demonstrate this.

To Unit Test AngularJS with Jasmine in Visual Studio

In this post, we will create an AngularJS controller, then write and run unit tests for it in Visual Studio 2013 using Jasmine and Chutzpah.

1) Install the Chutzpah Visual Studio Extension. 

2) Create a new ASP.NET Web Application (Empty) Project

Click OK. On the next screen, choose "Empty" project and click OK again.

Click OK. On the next screen, choose "Empty" project and click OK again.

3) Install the AngularJS.Core nuget package. From the package manager console (ALT+T,N,O) run:

install-package AngularJS.Core

4) Install the Jasmine test framework nuget package. From the package manager console, run:

install-package JasmineTest

The JasmineTest package includes a controller for ASP.NET MVC and some examples. Since we created an Empty web project, JasmineController.cs will not compile. Remove the Controllers and jasmine-samples folders. We won't need them.

Delete the highlighted content.

Delete the highlighted content.

5) (Optional) Create a sanity test to make sure Jasmine and Chutzpah are working.

Since Jasmine is just one of many unit testing frameworks we could use, we should make sure it is working before we take unit test failures seriously. To do this, let's create a simple sanity test. Create a directory at the root of the project called "Tests". Add a new Javascript file to the "Tests" directory called "jasmineWorks.js". In "jasmineWorks.js", add the following code:

describe( 'jasmine works', function () {
    it( 'sanity check', function () {
        expect( 0 ).toBe( 0 );
    } );
} );

As soon as we add this test, Chutzpah should detect it in the Test Explorer (if Text Explorer is not visible, show by going to Test -> Windows -> Test Explorer). 

6) Add a simple AngularJS controller

Let's create a simple AngularJS controller and see how to test it. Add a new file to the "scripts" directory called "appController.js" and add the following code:

angular.module( 'app', [] ).controller( 'appController', function( $scope ) {
    $scope.value = 5;
} );

7) Add a unit test for AppController

Inside the "Tests" directory, add a new Javascript file called "appControllerSpec.js". In it, add the following code:

/// <reference path="D:\VSScratch\NgUTJasmine\NgUTJasmine\scripts/angular.js" />
/// <reference path="D:\VSScratch\NgUTJasmine\NgUTJasmine\scripts/angular-mocks.js" />
/// <reference path="D:\VSScratch\NgUTJasmine\NgUTJasmine\scripts/appController.js" />

describe( 'When using appController ', function () {
    //initialize Angular
    beforeEach( module( 'app' ) );
    //parse out the scope for use in our unit tests.
    var scope;
    beforeEach( inject( function ( $controller, $rootScope ) {
        scope = $rootScope.$new();
        var ctrl = $controller( 'appController', { $scope: scope } );
    } ) );

    it( 'initial value is 5', function () {
        expect( scope.value ).toBe( 5 );
    } );
} );

The three reference directives at the top are needed by Chutzpah (alternatively, you can define a Chutzpah config file). The test assertion needs access to the scope, so we have to intercept it and store it in the scope variable using Jasmine's beforeEach function. 

8) Run your tests

If everything went according to plan, you should see the new test show up in the Test Explorer, where you can run it as you would any other test. 

Huge thanks to Matthew Manela, the author of Chutzpah. You have created a really useful extension that I use every day. 

To Unit Test Javascript with QUnit in Visual Studio

While Visual Studio (2013) is an excellent IDE, it lacks good native support for modern web development. Today, we will see how to unit test Javascript using Chutzpah and QUnit:

1) Install the Chutzpah Visual Studio Extension

In Visual Studio, go to Tools -&gt; Extensions and Updates.&nbsp;

In Visual Studio, go to Tools -> Extensions and Updates. 

Search Online for "Chutzpah" and install both the Test Adapter and Context Menu Extensions.

Search Online for "Chutzpah" and install both the Test Adapter and Context Menu Extensions.

2) Create a new ASP.NET Web Application (Empty) Project

On the next screen, choose "Empty"

On the next screen, choose "Empty"

3) Add a new Javascript file called calc.js with some simple logic in it:

//The functionality to test
function add( a, b ) {
    return a + b;
};

4) Add a second Javascript file called calcTests.js. At the top of the file, add a reference to the calc.js file so Visual Studio can locate the code-under-test like so:

/// <reference path="{path}" />
/// replace {path} with the path to your calc.js

5) Add test cases by using the "test" function defined by QUnit

/// <reference path="d:\vsprojects\JsUnitTests\JsUnitTests\calc.js" />

test( "Adding 0 and 0", function () {
    var result = add( 0, 0 );
    equal( result, 0, "should equal 0" );
} );

test( "Adding 4 and 5", function () {
    var result = add( 4, 5 );
    equal( result, 9, "should equal 9" );
} );

6) Run the Unit Tests from the Test Explorer by clicking "Run All"

If the Test Explorer is not visible, you can show it again from the Main Menu by going to Test -&gt; Windows -&gt; Test Explorer

If the Test Explorer is not visible, you can show it again from the Main Menu by going to Test -> Windows -> Test Explorer

In future posts, we will repeat this exercise with Jasmine and Mocha, two other popular Javascript unit testing frameworks. Luckily, the excellent Chutzpah extension works with all three.