Creating a simple REST like service with OWIN – Open Web Server Interface

"OWIN, a standard interface between .NET web servers and web applications. The goal of OWIN is to decouple server and application and, by being an open standard, stimulate the open source ecosystem of .NET web development tools." – owin.org

OWIN can be used for extremely lightweight hosts that can run from command line, Windows service, client, low power devices etc. Many applications today doesn't use all the features that IIS (Internet Information Service) provide use with, because we just doesn't need them.

In this blog post I will show you a very simple REST like service using OWIN (the code will just support easy GETs nothing more, so it's not a complete REST service).

OWIN is based on a very simple interface, it uses something called application delegate or AppFunc. An application delegate takes the IDictionary<string,object> environment and returns a Task when it has finished processing.

  using AppFunc = Func<
IDictionary<string, object>, // Environment
Task>; // Done

 

The dictionary has some keys that can be used to get access to request and response, headers, body, Query string, request method etc. You can find the key's in the OWIN specification (This blog post will mention some of them later).

In this blog post I will use Katana to host my OWIN and REST like service. To setup a simple OWIN application using Katana, take a look at this documentation (I will not give instruction how to set it up in this blog post).

An OWIN hosts can do the following when its starts:

It first creates properties with startup data or capabilities provided by the host. The properties is an IDirectory<string, object>. The host selects the server to be used and will provides it with the Properties collection, then it locates the application setup code and invokes it with the Properties collection. The application can then use the properties and decide its own requesting pipeline. Then the host invokes the server startup code with the properties and finish configure itself to accepting requests.

The OWIN namespace has the IAppBuilder interface, this will contain the Properties mentioned above. When using Katana a Startup class is needed with two methods:


public void Configuration(IAppBuilder app)

public Task Invoke(IDictionary<string, object> env)

 

The Configuration method will be called when the hosts is starting, and the IAppBuilder will be passed to the Configuration method. The Invoke will be called every time an incoming request should be handled. The env argument will contain a dictionary with environment information, such as request and response.

I created a simple solution to register "routes" and execute methods based on the requested path. Here is my Startup class:

 

public class Startup : BaseNavigation
{
public void Configuration(IAppBuilder app)
{
Get["/list/customers"] = ListCustomers;
Get["/list/users"] = ListUsers;

app.Run(this);
}

public Task Invoke(IDictionary<string, object> env)
{
switch (((string)env["owin.RequestMethod"]).ToUpper())
{
case "GET":
HttpGetHandler(env);
break;
//...

       }

return Task.FromResult<object>(null);
}

}

 

The BaseNavigation class inherited by the Startup class just contains a Get property:


public class BaseNavigation
{
Dictionary<string, Func<object>> _get = new Dictionary<string, Func<object>>();

public IDictionary<string, Func<object>> Get
{
get { return _get; }
}
}


In the Startup's Configuration method I use the Get property to set up which methods that should handle the request for a specific "route". The Get property will only be used to get the "routes" when the incoming request is a HTTP GET. Within the Startup class's Invoke method (as mentioned earlier, the Invoke method will be called on each request) I use the "env" argument to get access to the requested method, this is done by using one of the key specified ("owin.RequestMethod") in the OWIN specification.

If the request method is GET, I make a call to my HttpGetHandler that will handle the GET:

private void HttpGetHandler(IDictionary<string, object> env)
{
var responseContent = Get[(string)env["owin.RequestPath"]].Invoke();

var requestHeader = (IDictionary<string, string[]>)env["owin.RequestHeaders"];
var responseHeader = (IDictionary<string, string[]>)env["owin.ResponseHeaders"];

responseHeader.Add("Content-Type", requestHeader["Accept"]);
env["owin.ResponseStatusCode"] = 200;

using (var writer = new StreamWriter((Stream)env["owin.ResponseBody"]))
{
new JsonSerializer().Serialize(writer, responseContent);
}
}

 

NOTE: I don't care about the HTTP Headers "Content-type" or "Accept" header to decide the format for the returned response, I simply use JSON, the goal is not to write a perfect REST infrastructure, just a simple demonstration of OWIN, there are no error handlers is added to the code.

By using the "owin.RequestPath", I can get access to the request path, for example if I do GET http://localhost/list/customer, the "list/customer" will be the request path. Because the key value of the BaseNivgation's Get property is the request path, I just use the path as a key and invoke the Func<T> registered, in this case when "list/customer" is the request path, the ListCustomers method will be executed. To demonstrate how we can get access to the request and response header, I simply gets the "owin.RequestHeaders" and "owin.ResponseHeaders", and adds the "Content-Type" to the response header with the value of the request headers "Accept" header.

To write to the response stream of a request, the "owin.ResponseBody" key of the "env" argument can be used. The "owin.RequestBody" can be used to get the stream of the request body.

By setting the "env"'s "owin.ResponseStatusCode", I can specify the HTTP status of the request, in this case 200 (which is also default).

Here are the ListCustomers and ListUsers methods and the Customer and User classes:

public IEnumerable<Customer> ListCustomers()
{
return new[] { new Customer() { Id = 1, Name = "John Doe" } };
}

public IEnumerable<User> ListUsers()
{
return new[] { new User() { Id = 1, Name = "Super User" } };
}


public class Customer
{
public int Id { get; set; }

public string Name { get; set; }
}

public class User
{
public int Id { get; set; }

public string Name { get; set; }
}

 

Summary

 

In this blog post you have seen how OWIN and Katana was used to create a simple REST like service (well, far from a complete one). The idea was to show some basic stuffs that can be done by using OWIN.

 

If you want to know when I publish a new blog post, feel free to follow me on twitter: @fredrikn

No Comments