1. Introducing OWIN
Some working code examples accompanying this blog post can be found here.
To better explain what OWIN is and how Microsoft and its development community got there, we should firstly examine the evolutionary context of ASP.NET technologies in recent years.
Microsoft’s first server-side scripting technology released back in 1996 was Active Server Pages (ASP), a script you could happily mix with HTML mark-up to produce dynamic front-end code. ASP was later superseded by the ASP.NET framework in 2002, an opportunity for Microsoft to bring its ASP web development into the 21st century by combining it with an object-oriented language (C # or VB.NET) and access to the Base Class Library (BCL). That’s how ASP.NET WebForms was born.
Since then, all ASP.NET projects from Microsoft have been based on the System.Web assembly. System.Web contains many of the classes responsible for http-protocols, requests creation and sending. System.Web relies heavily on IIS - Microsoft’s general-purpose designed for the Windows OS. Check out this article to learn more about it (coming soon).
There are several disadvantages to this reliance on System.Web and IIS:
It was originally designed for ASP.NET WebForms released back in 2002 and must now universally support applications developed over the last two decades. Consequently, it lacks portability, modularity and scalability.
The System.Web namespace includes a number of default components which, irrespective of their use in the program, are attached to the Http pipeline. This means that for every request, some unwanted features end up executed which degrades the performance.
It is bundled as part of the .Net framework installer package. This means that it is only updated with new .NET releases and can take several years between each new version. That's disadvantageous in a world of web development that has exploded in recent years and changes constantly.
In order to confront these issues, Microsoft took advantage of the craze around ASP.NET MVC and other newer ASP.NET technologies to review its strategy around the System.Web assembly.
OWIN would later come to break this dependency.
However, the concepts and ideas behind OWIN first appeared with the ASP.NET Web API. A framework realeased in 2010 for building HTTP based services.
The ASP.NET Web API was delivered in the form of several modules which do not depend on what is necessary for hosting the application. Therefore, do not need to reference System.Web or use any of its types decoupling it from the IIS ball and chain.
In practice, it is even quite easy to host a Web API application in a console application or a Windows service.
The Web API therefore laid the foundations towards a new way of thinking for the development and hosting of server-based applications.
In this emerging approach, applications must be developed as lightweight as possible and above all, capable of integrating with any type of application server.
Microsoft was indeed able to achieve these goals with the ASP.NET Web API, but those concepts also had to be carried over to its other technologies. And that's when OWIN entered the scene.
You can learn about the ASP.NET Web API here. (Coming soon!)
2. So what's it all about?
OWIN stands for Open Web Interface for .NET. This name actually represents a standard, a sort of norm, which defines an abstraction layer between the code of your applications and your server.
The goal is to be able to port an application from a server and host it within another type of server.
An application written in compliance with the standards defined by OWIN is no longer strongly coupled with IIS.
That being said, OWIN is not designed to replace the entire ASP.NET framework or IIS as such. You will still end up with a number of references to System.Web assemblies and associated HTTP handlers written in the web.config configuration file when creating a new ASP.NET MVC application.
For this reason, the big idea behind OWIN is that when creating a new application, the goal should not be to start from something already strongly linked to IIS, but rather to start from the bare minimum and gradually build up additional functionalities.
It is an approach that can also be found in other trendy Web technologies such as node.js.
Thanks to this, it’s a lot easier to use .NET applications with an alternative web or application server.
Furthermore, by having removed the dependency with the System.Web assembly, Microsoft is able to deliver its OWIN web stack updates faster through its Nuget package manager.
All information about OWIN is available on the official website at http://owin.org/.
Keep in mind that OWIN is only a specification and not an implementation. By being an open standard, it also aims to nurture open source community participation within the .NET ecosystem of web development tools.
3. What is middleware?
OWIN is used to write middlewares.
Before looking at how we implement the Owin specification, let's try to understand what a middleware is.
The concepts of HTTPModule and HTTPHander are easily recognised by those coming from the ASP.NET world of web development. These are used to intercept the request-response dynamic between an application and server and implement some specifically made logic through custom modules or handlers.
OWIN works as a pipeline in which a request coming from server to the web application passes through multiple components. Each component can inspect, modify, redirect or provide a response to the request. The response is then served back to the user.
The pipeline:
What is the the OWIN Environment Dictionary? Contains all necessary request, response information and server/host information. A minimum set of keys and values must be present in the dictionary as set out in the OWIN Specification. This Dictionary object is which means that servers, host environments, middleware, and application code may add additional data, or change the data in the dictionary during processing. this is just a property bag that gives you access to the request headers, request stream, response headers, response stream and server data
4. Coding with OWIN
_Relevant for .NET Framework, tested up to Framework 4.8 _
Remember. OWIN itself is a specification to follow, a sort of contract, and not made up of any tools, libraries or anything else. This specification is listed at the following link http://owin.org/html/spec/owin-1.0.html.
The implementation of this specification is found within the IAppBuilder interface in the Owin Assembly.
namespace Owin
{
public interface IAppBuilder
{
IDictionary<string, object> Properties { get; }
object Build(Type returnType);
IAppBuilder New();
IAppBuilder Use(object middleware, params object[] args);
}
}
At its lowest level, an OWIN middleware component is constructed with the following signature:
Func<IDictionary<string, object>, Task>
This generic Func takes a Dictionary object (IDictionary<string, object>) known as the OWIN Environment Dictionary and returns a Task object.
Every component in the OWIN pipeline must implement this simple delegate structure commonly referred to as the Application Delegate.
The above signature is also called AppFunc
and in order to improve readability, you’ll often see it aliased at the top of your class like so
using AppFunc = Func<IDictionary<string, object>, Task>;
As we saw in section 3, the environment dictionary is populated by the OWIN host with all the information needed to perform whatever processing required by the request, a Task is then returned which signals that the HTTP application has finished processing the request.
In order to work with OWIN, we use AppFunc as the in and out parameters of another yet Func object. You don’t need to use the alias but I certainly recommend you do for the sake of readability.
Func<in AppFunc, out AppFunc>
So, what the heck is happening here? As explained in section 3, OWIN models its application as Middleware components layered in a pipeline. A middleware component takes as an argument the next middleware component to call and returns an AppFunc with the information for the next request.
Some processing may be performed on the request, or it may be forward to the next Middleware or we can intentionally return a response immediately and short-circuit the chain if appropriate.
To put it another way, a Middleware acts as a proxy, encapsulating and hiding the next Middleware in the chain.
What is a Func? A Func is one of the C#’s built-in delegate. It receives arguments and returns a value. Check out this article to explores Func in greater detail. (coming soon)
So how do we set an OWIN pipeline into motion?
The IAppbuilder has four methods for adding middleware to OWIN. One in Owin.dll
, and another 3 extension methods in Microsoft.Owin.dll
.
• app.Use()
inserts a middleware into the pipeline. You’re then required to call next.Invoke() to call the next middleware. There are two versions of this method that we will cover later.
• App.run()
inserts a middleware without a next, so it only runs that middleware.
• App.map()
let’s you map path patterns which are evaluated per request at runtime. Such middleware then runs according to the pattern you mapped.
Let’s see how this all works in the next section with code for a bare minimum .NET 4.x self-hosted HelloWorld web application running from a console window.
5. Hello World with Owin
Let's see the basic implementation possible.
If you want to follow along, keep in mind that you don't need to create a project from a web application project template because the whole point of self-hosting is that you control the hosting. You can even make a console app like in the example projects
We’re going to need four NuGet packages;
Owin,
Microsoft.Owin,
Microsoft.Owin.Hosting
Microsoft.Owin.Host.HttpListener
However, there is a dependency from Microsoft.Owin.Hosting to Owin and Microsoft.Owin so actually you just need to execute the following two commands in the package manager console:
install-package Microsoft.Owin.Hosting
install-package Microsoft.Owin.Hosting.HttpListener
Now, here's the code:
using System;
using Microsoft.Owin.Hosting;
using Owin;
namespace Owin01_Helloworld {
class Program
{
public static void Main(string[] args) {
var url = "http://localhost:8080/";
var startOpts = new StartOptions(url);
using (WebApp.Start<Startup>(startOpts)) {
Console.WriteLine("Server run at " + url + " , press Enter to exit.");
Console.ReadKey();
}
}
}
}
This is a standard console program with a common Main method. The WebApp.Start
method will start an application of type Startup
with the url http:/localhost:8080
. The next thing we need to do is write the application itself, that is, the Startup
class.
This is a standard console program with a common Main
method. The WebApp.Start
method will start an application of type of type Startup
with the url http:/localhost:8080.
The next thing we need to do is write the application itself, that is, the Startup
class.
using Owin;
namespace HelloOwin
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use((context, next) =>
{
context.Response.Write("Hello World");
return Task.FromResult(0);
});
}
}
}
We use the Configuration
method as per .NET convention which accepts an IAppBuilder
object.
Owin trivia: For performance reasons, multiple calls to
Use()
,Run()
, andMap()
are discouraged.OWIN
components work best when grouped together.
6. Pass - Response
Now, how do we write a middleware that uses the pass-response paradigm of the OWIN pipeline discuss in section 3?
Remember that in the OWIN pipeline, each middleware component is responsible for invoking the next component in the chain.
app.Use(async (context, next) =>
{
var timer = new Timer();
timer.Start();
await next();
timer.Stop();
Console.WriteLine("Request took {0} ms", timer.ElapsedMilliseconds);
});
We use await next()
.
Next is an alias for the Func<>
that connects our pipeline to the next middleware.
7. IOwinContext
In the examples we’ve seen so far, we’re passing the IOwinContext
as a parameter.
app.Use((context, next) =>
The IOwinContext
is a wrapper for the OWIN
environment dictionary and includes all you need to know about the current context, which is essentially the current request.
8. The OwinMiddleware
You’ll see that Intellisense will give you 2 variations of the method when you start typing app.Use()
.
The one we've seen so far,
public static IAppBuilder Use(this IAppBuilder app, Func<IOwinContext, Func<Task>, Task> handler);
and one that takes an object and an array of parameters.
public static IAppBuilder Use<T>(this IAppBuilder app, params object[] args);
Both of them do the same thing: registering code as middleware.
The one we've used is not first place, it's specified as an extension method that Microsoft has provided us with.
Microsoft has provided a base class to use which is better than using the more complex Func<>
that we've been using until now.
Unsurprisingly, it’s called the OwinMiddleware
! It’s pretty straightforward and works to nicely encapsulate our middleware into a reusable form.
Applying the OwinMiddleware to our timer example in section 6 looks like this:
public class SimpleDiagnosticsMiddleware: OwinMiddleware
{
public SimpleDiagnosticsMiddleware(OwinMiddleware next) : base(next)
{
}
public async override Task Invoke(IOwinContext context)
{
var timer = new Timer();
timer.Start();
await next();
timer.Stop();
Console.WriteLine("Request took {0} ms", timer.ElapsedMilliseconds);
}
}
As you can see, it's a little more readable and registering it feels a lot cleaner.
public void Configuration(IAppBuilder app)
{
app.Use<SimpleDiagnosticsMiddleware>();
}
9. Owin as type and instance
We can also write our middleware as a separate class.
namespace Owin03_Middleware {
using AppFunc = Func<IDictionary<string, object>, Task>;
public class LogMiddleware {
private readonly AppFunc next;
public LogMiddleware(AppFunc next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
Console.WriteLine("LogMiddleware Start.");
await next(env);
Console.WriteLine("LogMiddleware End.");
}
}
}
Then we can register it as a type using app.Use<>()
in our Startup.Configuration()
method.
public void Configuration(IAppBuilder app) {
app.Use<LogMiddleware>();
}
You can also include additional constructor arguments to pass to your middleware:
app.Use(typeof(MyMiddlewareClass), new object());
We can also create an instance of our middleware.
We can also make instances of our middleware to pass to the IAppBuilder
methods.
using AppFunc = Func<IDictionary<string, object>, Task>;
public class InstanceMiddleware {
private AppFunc next;
public void Initialize(AppFunc next) {
this.next = next;
}
public async Task Invoke(IDictionary<string, object> env) {
Console.WriteLine("InstanceMiddleware Start.");
await next(env);
Console.WriteLine("InstanceMiddleware End.");
}
}
var instance = new InstanceMiddleware();
app.Use(instance);
Initialize is called automatically when the IAppBuilder
is first built.
This is useful if you want to create your middleware ahead of time such as when using dependency injection.
Finally, The last bit to have a look at is how we can have OWIN use different configurations for different areas.
To do this, we use the extension method called Map(). It takes the path to look for, and a configuration callback to create the configuration to use for the specified area. Like this
app.Map("/authentication", app2 =>
{
app2.Use<AuthenticationMiddleware>();
app2.Use((context, next) =>
{
context.Response.Write("User Authenticated");
return Task.FromResult(0);
});
});
What’s going on is that any call that has a path beginning with "/authentication " will route to the LogInMiddleware and return "User Authenticated."
This functionality is very cool because it means we can have several settings in different "areas" of our program. And if we encapsulate our middleware in the classes of OwinMiddleware, it will be simple and very readable to create these specific pipelines!
This lets us keep several different configurations in different areas of our app. Mapping makes building up our Owin middleware pipelines easy and readable.
10. Modularizing OWIN
We can easily package our OWIN middleware using custom extension methods for cleaner, reusable code.
Extension methods can only be added to static classes as static methods.
public static class AuthenticationMiddlewareExampleExtensions
{
public static void AuthenticationMiddleware(this IAppBuilder app)
{
app.Use<AuthenticationMiddleware>();
}
}
Then simply adapt the example above.
app.Map("/authentication", app2 =>
{
app2.AuthenticationMiddleware();
...
});
And if we wanted to add configuration, this could obviously just be passed in as a parameter to the UseSimpleDiagnostics()
method and then passed on to the middleware class, making the registration nice and clean.
And if we were to incorporate code, this could naturally only be passed into the app2.AuthenticationMiddleware()
method as a parameter, and then passed on to the middleware class, making its registration nice and tidy.
11. OWIN in .NET CORE
In ASP.NET Core, web apps are actually just .NET Core console apps setup to process incoming HTTP requests. This concept further aligns .NET CORE with the overall approach Microsoft has taken with microservices architecture support.
12. Summary
As a budding new web developer, you should be able to disregard OWIN.
However, in order to ensure that your code is future proof, then you should start lessoning your reliance on System.Web (such as HttpContext) and switch to OWIN instead.
That means that if you're writing middleware, such as authentication modules, prioritise making them an OWIN middleware, rather than a standard HttpModule.
The key points discussed in this post:
The aim of OWIN is to decouple the application from the server and help to male ASP.NET become more modular and scalable
Which makes it more easy to run and deliver lightweight environments than the traditional IIS (e.g. with Mono on your home Raspberry).
It can be easily ported to different environments, and thus making it competitive with other open source competitors.
Other key things to keep in mind:
OWIN is a specification. Microsoft's implementation is Katana.
How does the application communicate with the server? Simply via the application delegate which employs an environment dictionary.
Bon middlewares ! Happy middlewaring