In my last couple of posts, I have talked about OWIN. What it is, how it works, why it is interesting and so on. I have talked mostly about the hosting side of it, and a bit about how we can plug into the OWIN pipeline using what is called middleware… However, so far, the middleware has been ridiculously simple, and done very little, which isn’t really helpful I guess. And besides not doing very much interesting work, they have also not interacted very much with the request pipeline. Most of them, or maybe even all of them, have just terminated the pipeline and returned a simple response…
In this post, I want to take a look at how OWIN abstracts the server, and the request and response, and also how we can use this abstraction to extend the functionality of our pipeline.
OWIN has a very simple way of abstracting the system it is running on. It takes all the information needed to process the request, and return a response, into a dictionary. The dictionary is declared as IDictionary<string,object>, which is ridiculously generic. But it is this generic nature that makes it so powerful! As the value is of type “object”, it means that the code interacting with the dictionary can put anything they want into it.
When the HTTP request comes into the server, it parses it and divides it into useful pieces that we can use. These pieces are things like headers and path and so on. All of these pieces are then put into the dictionary with pre-defined names. However, it also puts other kinds of useful pieces of information into the dictionary. Things like the OWIN version that the server is running, and different host information. All things that you, as an app developer might be interested in, and that might affect the processing of the request. It then takes this dictionary and sends it to the first available middleware, which processes its content, and then either returns it back, or passes it on to the next piece of middleware for processing…
Pulling out a list of keys available in the dictionary could result in something similar to this
"owin.RequestHeaders"
"owin.ResponseHeaders"
"owin.Version"
"owin.RequestProtocol"
"owin.RequestScheme"
"owin.RequestMethod"
"owin.RequestPath"
"owin.RequestPathBase"
"owin.RequestQueryString"
"owin.CallCancelled"
"server.OnSendingHeaders"
"owin.ResponseBody"
"owin.ResponseStatusCode"
"owin.RequestBody"
"host.TraceOutput"
"host.AppName"
"host.AppMode"
"host.OnAppDisposing"
(Note: This is pulled out from a request using the OWIN test server that Microsoft has on NuGet, so it might differ from a “real” server like IIS)
But it doesn’t stop there. The server can also offer functionality through this dictionary. There are already a couple of extensions defined for OWIN, which are implemented by adding things to the dictionary. For example, sending files is an extension that a server can implement like this…
So, how does the server do it? Well, it is actually quite simple. If the server offers any of these extra pieces of functionality, it exposes it by adding an item of type Action<> or Func<> (or similar) to the dictionary. The other middleware can then just look at the dictionary to see if it is available, and if it is, just pull it out and call the method…
As you can see, it is really a quite brilliant way of abstracting the server. Any server can implement this easily! And any developer can consume it easily… And it can be extended basically without limitations!
As far as I understand it (I am sitting on a plane on my way to TechEd 2014 so I can’t verify it) the OWIN initiative doesn’t really specify exactly how this dictionary is passed around. It just defines that it should. So in Microsoft’s implementation, the dictionary is exposed through and interface called IOwinContext. This interface has a property called Environment, which holds the dictionary instance for the current request. It also offers a couple of wrappers for the request and response, so you don’t have to mess with the dictionary for the regular things you work with. But they are just wrappers. All the information is still available in the dictionary. But having some helpers makes things a lot easier.
The IOwinContext also exposes a property to help with tracing, and one to integrate with the user authentication/authorization. But in general, once again, those things are just helpers to make development easier…
The Microsoft implementation also includes a base class, OwinMiddleware, that can be used to simplify some things when building middleware. However, if your middleware intends to sometimes short circuit the pipeline and return a response instead of just watching, and manipulating, the information on the way in and out, then you have to do it yourself…
But how about I stop talking/writing, and show some actual code…
I will start out by creating a simple piece of middleware that will return a response in all situations. It will be really simple, and very similar to what I have implemented in previous posts, but with a twist when it comes to the packaging…
I create a new class called HelloWorldMiddleware, and add this piece of code to it
public class HelloWorldMiddleware
{
public Task ProcessMessage(IOwinContext context, Func<Task> next)
{
var response = "Hello World! It is " + DateTime.Now.Ticks;
context.Response.Write(response);
return Task.FromResult(0);
}
}
As you can see, I have encapsulated my functionality in a class, instead of just adding it to the IAppBuilder instance using a lambda expression. This makes it more reusable, in case you would like to reuse this piece of awesomeness…
Next I wire up my middleware in my Startup class like this
app.Use(new HelloWorldMiddleware().ProcessMessage);
I won’t cover the basics of the Startup class etc in this post, as I will just assume you already know how to do it. If not, go back and read my previous 2 posts…
The other way to wire it up would be to create an extension method for the IAppBuilder interface. This is generally the way people do it. Especially for middleware that returns responses (which might not be middleware but applications…but you get it…)
To do so, I just take my call to Use() and wrap it in an extension method like this
public static class AppBuilderExtensions
{
public static void UseHelloWorld(this IAppBuilder app)
{
app.Use(new HelloWorldMiddleware().ProcessMessage);
}
}
On top of that, you could use the extension method called Run() instead of Use(). Run expects your middleware to return a response instead of handing the request on to the next middleware…
Once I have my HelloWorldMiddleware in the pipeline, I can run it and get a response. This is something you have seen before, so let’s carry on with something a little bit more complicated. Let’s add a piece of middleware that offers _very_ rudimentary caching. About as rudimentary and contrived as my HelloWorldMiddleware. But the goal isn’t to spark a new OSS project. it is just to show a concept…
The next middleware I create is called…wait for it…wait for it…CachingMiddleware! Tadaaa!
It uses an in-memory dictionary to keep track of cached responses, and their expiry time… The basics of it looks like this
public class CachingMiddleware
{
private readonly IDictionary<string, CacheItem> _responseCache = new Dictionary<string, CacheItem>();
...
public void AddToCache(IOwinContext context, string response, TimeSpan cacheDuration)
{
_responseCache[context.Request.Path.Value] = new CacheItem { Response = response, ExpiryTime = DateTime.Now + cacheDuration };
}
private class CacheItem
{
public string Response { get; set; }
public DateTime ExpiryTime { get; set; }
}
}
As you can see, it really isn’t that complicated. It creates a dictionary at creation time, which is used as an in-memory cache. It uses the IOwinContext to get hold of the request path which is then used as the key for the cached item.
As it is a really simple implementation, the application will be responsible for adding things in there manually. A more complex and fully fledged caching solution could just look at the response’s cache headers and figure it out on its own. But this is a simple, contrived example…
So far however, it does have logic for a simple cache, but it doesn’t really do much. So to remedy that, I will add a “middleware method” that will “plug-in” the cache into the pipeline.
It looks like this
public Task ProcessMessage(IOwinContext context, Func<Task> next)
{
context.Environment["caching.addToCache"] = new Action<IOwinContext, string, TimeSpan>(AddToCache);
var path = context.Request.Path.Value;
if (!_responseCache.ContainsKey(path))
{
return next();
}
var cacheItem = _responseCache[path];
if (cacheItem.ExpiryTime <= DateTime.Now)
{
_responseCache.Remove(path);
return next();
}
context.Response.Write(cacheItem.Response);
return Task.FromResult(0);
}
Ok, so let’s go through this step by step.
The first line is by far the coolest! It takes the Environment dictionary and adds an entry called “caching.addToCache”. The value of the entry is an Action<> that takes 3 parameters. The Action<> in turn references the AddToCache() method. That way, any middleware further down the line can just look for the availability of a cache, and add stuff to it if it wants to…
Next, I pull out the requested path, and see if my cache contains anything for that path… If it doesn’t, then obviously nothing has been cached, and I pass the request on to the next middleware. If there is something in the cache, I check to see if it is still valid. If it isn’t, I pull it out of the cache, and pass the request on to the next.
However, if there is something in the cache, and it is still valid, I return that, instead of passing control on to the next middleware…
That my friend, is a _very_ rudimentary cache implemented in just a few lines…
The next thing is to plug this into the OWIN pipeline as one of the first, if not _the_ first pieces of middleware… In my case, I add another IAppBuilder extension method, and register my middleware components like this
app.UseCaching();
app.UseHelloWorld();
But before anything is actually cahced, I need to modify my HelloWorldMiddleware to handle caching… It does so by checking if any caching is available, and if it is, it pulls out the “cache action” and puts its response in the cache, before returning the response…
public Task ProcessMessage(IOwinContext context, Func<Task> next)
{
var response = "Hello World! It is " + DateTime.Now.Ticks;
if (context.Environment.ContainsKey("caching.addToCache"))
{
var addToCache = (Action<IOwinContext, string, TimeSpan>) context.Environment["caching.addToCache"];
addToCache(context, response, TimeSpan.FromMinutes(10));
}
context.Response.Write(response);
return Task.FromResult(0);
}
Ok, if you now run this application and create 2 request within 10 minutes, you will get the exact same response, which is visible as the response contains DateTime.Now.Ticks…
That’s all there is to it. There are a bunch of different ways to do this, as always with programming. But this was one way at least. Very simple, yet very powerful!
As mentioned before, there are loads of Authorization middleware available for you to use, which makes it real easy to secure your applications. And even though the security area seems to be the area that offers the largest selection of middleware, I expect you to see a lot more coming very soon.