BT

ASP.NET Core - The Power of Simplicity

| Posted by Chris Klug Follow 0 Followers , reviewed by Jeff Martin Follow 12 Followers on May 13, 2018. Estimated reading time: 12 minutes |

A note to our readers: You asked so we have developed a set of features that allow you to reduce the noise: you can get email and web notifications for topics you are interested in. Learn more about our new features.

Key Takeaways

  • OWIN gives developers a nice abstraction of the webserver when building web applications
  • ASP.NET Core steps away from the standard OWIN implementation, but does it to simplify for developers
  • Simplifying a complex thing using an abstraction doesn't make it less powerful, it just makes it simple to work with
  • By using middlewares instead of high level frameworks, developers can build lean, but still powerful applications
  • Even if you aren’t using ASP.NET Core, you can still get a lot of these features by using Project Katana in older solutions

With the release of .NET Core 2.0, Microsoft has the next major version of the general purpose, modular, cross-platform and open source platform that was initially released in 2016. .NET Core has been created to have many of the APIs that are available in the current release of .NET Framework. It was initially created to allow for the next generation of ASP.NET solutions but now drives and is the basis for many other scenarios including IoT, cloud and next generation mobile solutions. In this series, we will explore some of the benefits .NET Core and how it can benefit not only traditional .NET developers but all technologists that need to bring robust, performant and economical solutions to market.

This InfoQ article is part of the series ".NET Core". You can subscribe to receive notifications via RSS.

 

When Microsoft decided to reimagine its web development platform ASP.NET, they decided that having it tied to IIS might not be such a great idea. The fact that the original ASP.NET was built on IIS specific technology made it not only tied to Windows, but also impossible to self-host; limitations that don’t quite cut it in the new cloud centric world. Instead, Microsoft decided to go all-in on Open Web Interface for .NET, or OWIN as it’s also known, and abstract away the webserver completely. This allows the framework, as well as its users, to completely ignore which server is responsible for accepting the incoming HTTP requests, and instead, focus on building the functionality that is needed.

OWIN isn’t a new concept though. The OWIN specification has been around for quite a few years, and Microsoft has allowed developers to use it while running under IIS for almost as long, through an open source project called Project Katana.  In reality, Microsoft hasn’t just allowed us developers to use it through Katana, it has been the foundation for all ASP.NET authentication functionality for several years.

So, what is OWIN really? To be honest, it’s fairly simple! And the simplicity is actually the thing that makes it so great. It’s an interface that manages to abstract away the webserver using only a predefined delegate and a generic dictionary of string and object. So instead of having an event driven architecture where the webserver raises events that you can attach to, it defines a pipeline of so called middlewares.

A middleware is a piece of code that interacts with the requests coming from clients. (And yes, I intentionally kept it very generic by saying “a piece of code”). It can be implemented in a couple of different ways. A delegate with the right signature is all that is needed, even if a class based version is preferred in most cases. The code can inspect, and potentially modify the request as it arrives from the client, as well as the response that is returned to the client. And if it wants to, it can even decide to generate the response that is sent to the client on its own.

The middlewares are then put together in a pipeline, where the incoming message is passed from middleware to middleware in the order which they were added to the pipeline, until one of the middlewares decides that it knows how to generate a response, and does so. It then passes the response back through the pipeline to be inspected, and potentially modified by the middlewares on the way back to the client. Very simple, but still very flexible and powerful.

This process is called a request pipeline, which makes it easy to imagine the message flowing through a pipe, having middlewares interacting with it as it flows past. However, a pipeline would require some form of pipeline object to be responsible for passing the message from middleware to middleware. In OWIN, the middlewares are actually more like a linked list. The incoming request is passed to the first middleware in the list, which then passes it on to the next when it is done. The request being passed from middleware to middleware until one of them generates a response and sends it back up the list again, allowing previous middlewares to inspect the outgoing message, at least at a high level. In reality, the process is a bit more complicated as the response is actually sent to the client as soon as it has been generated, even before it has been passed up the pipeline. This makes it a little bit more complex to modify the outgoing response, but for the sake of simplicity, let’s just ignore that piece.

The OWIN specification defines the incoming request as a dictionary of string and object. The server accepts the incoming HTTP request, splits the request information into usable pieces and places them in a dictionary, before passing it onto the first middleware for processing. It adds things like the request path, a headers collection, a stream containing the body and so on to the dictionary, using predefined keys. Using these well-known keys, the middlewares can then read the required information from the dictionary, and figure out what needs to done. However, the server also adds objects used for the response, like a response stream and a response headers collection to the dictionary, allowing the middlewares to generate a response to send to the client by using the objects in the dictionary. On top of that, the server can actually expose extra functionality to the middlewares by providing delegates in the dictionary. There is, for example, an OWIN specification extension which allows the server to provide a specialized way to send files to the client. This is exposed to the middlewares by providing a predefined delegate as an object in the dictionary. The middlewares can then query the dictionary to see if the currently used server supports that feature or not, and if it does, get hold of the delegate and call it to send back a file.

The OWIN interface is ridiculously simple, but also extremely powerful. It offers us low-level access to the HTTP requests and response, while at the same time abstracting away the nitty gritty details of handling the actual request. However, it does it without limiting the ability to offer higher level abstractions through delegates in the dictionary. On the other hand, it is VERY low level, and it does make some things a little cumbersome, which I guess is why Microsoft decided to embrace OWIN, but in their own way.

When Microsoft added the OWIN pipeline to ASP.NET Core, they made some changes to it. Or rather, they added their own layer on top of it, to make it a bit easier to work with. (At least that is the way I see it). Instead of just supplying the middlewares with a generic dictionary, they added a typed layer on top of it to make it easier to use. So, instead of getting a dictionary, you get an HttpContext object, which allows us to interact with the request and response in an easier way. For example, instead of writing ((Stream)dictionary[“owin.RequestBody”]).Write(…) to write a response to the client, you can write httpContext.Response.Body.Write(…). It’s not a huge difference, but not having to remember the correct key to use, and to cast to the correct type, makes it a lot less error prone.

In Project Katana, the HttpContext was just a wrapper on top of the dictionary, giving us typed access to the items in it. In ASP.NET Core on the other hand, it is a completely custom object. However, there are extensions available to give us a “proper” OWIN API in case we want to use an OWIN-based middleware.

 So, are we really going to build applications using a low-level API like this? Of course not! It’s fairly easy to build higher level abstractions on top of this low-level API, which is exactly what Microsoft has done. In ASP.NET Core, ASP.NET MVC is implemented as a middleware. It’s supported by several services that are injected into the middleware using .NET Core’s dependency injection functionality, but in the end, it is a middleware that is responsible for the interaction with the client requests. And this is where this very basic, low-level API shows its potential.

As we can register as many middlewares as we want in the request pipeline, we can mix and match the frameworks and features we want to use. Want to use ASP.NET MVC for your UI? No worries, just add the MVC middleware and supporting services. Want to use NancyFx for your API? No problem, just add it to the request pipeline. Want to use Facebook authentication? Once again, not a problem! Just add the required middlewares and services. Want to combine Twitter authentication, with JWT bearer tokens for your API? Just add the middlewares. I’m pretty sure you get it… This simple interface allows us to mix and match the things we need, combining 3rd party middlewares with our own custom-built ones, creating a completely custom request pipeline that fits our needs. And on top of that, if there isn’t a middleware handling the request, nothing will. For example, if you don’t add the static files middleware to the pipeline, it won’t even serve static files from disc. This is very different from hosting ASP.NET in IIS, where some of the functionality came out of ASP.NET, and some out of IIS.

I can’t really write an entire article about the request pipeline in ASP.NET Core, and not have a single line of code to show how it works. So, let’s use authentication as an example. It’s one of the most common ways to get in contact with OWIN for the first time, as well as provides a great example of the power that the interface offers, so it seems fitting to use here.

Adding authentication to an ASP.NET Core web application means adding a couple of things to the application. First of all, we need to add the authentication services to the services collection. And then we need to tell it the different types of authentication we want to support.

Say that we want to authenticate users using Facebook, and once they have been authenticated, we want to sign them into the application using cookie authentication. That configuration would look something like this

public void ConfigureServices(IServiceCollection services) {

		services.AddAuthentication(CookieAuthenticationDefautls.ApplicationScheme)

			.AddFacebook(“### CLIENT ID ###”, “### CLIENT SECRET ###”)

			.AddCookie();

}

Once we have the services in-place, we need to add the authentication middleware to the request pipeline like this

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
        // Middlewares that don’t require authenticated users
        app.UseAuthentication();
        // Middlewares that might require authenticated users
}

And finally, when we want to send a user to Facebook for authentication, we just call

await HttpContext.ChallengeAsync(

		new AuthenticationProperties { RedirectUri = "/userinfo" },
 
		FacebookDefaults.AuthenticationScheme);
}

This call will use the defined authentication scheme to set up the HttpContext to redirect the user to the correct login page. In this case, that means that the Facebook authentication handler sets the returned status code to HTTP 302 to make the response a redirect, and the location header to the Uri needed to get the client authenticated by Facebook, to redirect to that address. Once the user has been authenticated by Facebook, and is being redirected back to the application with the identity token, the authentication middleware catches that callback and uses the Facebook service to validate the token. If everything is OK, it then asks the cookie authentication service to issue a cookie that is used to keep the client signed in. In reality, that just means the cookie authentication service adds a header to the dictionary of response headers on the HttpContext, which is then added to the response to the client when the authentication service finally redirects the client back to the Path defined in the AuthenticationProperties.RedirectUri property.

So, using a couple of extension methods to register some services and a middleware, we have set up a fairly complex authentication flow that both redirects the user when requested to get authenticated, and handles the callback from the identity provider when authentication has taken place.

Note: In the previous configuration, it will actually try to authenticate the user using cookie authentication instead of Facebook by default when challenging a user. But it is just a small configuration change to make it use Facebook as the default instead, but that’s a bit beyond the scope of this article.

I hope that I have managed to convince you that this move to an OWIN-based pipeline in ASP.NET Core is a great thing. It might be a very simple and low-level interface, but it packs a massive punch when used in the right way. Creating a simple to use interface that allows for both low-level and high-level usage, and doesn’t limit what can be done in the future, is no easy task. But I do believe this interface does just that. Now it is up to us to make the most out of it! There are very few limitations if you are just a little creative-- it’s just a question of what problems you need to solve.

About the Author

Chris Klug is a software developer and architect at tretton37 in Stockholm, Sweden. He has spent the better part of his life solving problems by writing software, and he loves the creative side of coding as well as the challenges it continuously provides. He also spends a significant amount of his time presenting at developer conferences around the world--something that has apparently caught Microsoft's attention as they have awarded him Microsoft MVP for seven years running. But when asked, he has no problem admitting that he would much rather be kite-boarding on a nice beach or having one of his tattoos extended than playing with his computer.

 

With the release of .NET Core 2.0, Microsoft has the next major version of the general purpose, modular, cross-platform and open source platform that was initially released in 2016. .NET Core has been created to have many of the APIs that are available in the current release of .NET Framework. It was initially created to allow for the next generation of ASP.NET solutions but now drives and is the basis for many other scenarios including IoT, cloud and next generation mobile solutions. In this series, we will explore some of the benefits .NET Core and how it can benefit not only traditional .NET developers but all technologists that need to bring robust, performant and economical solutions to market.

This InfoQ article is part of the series ".NET Core". You can subscribe to receive notifications via RSS.

Rate this Article

Adoption Stage
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread
Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Discuss

Login to InfoQ to interact with what matters most to you.


Recover your password...

Follow

Follow your favorite topics and editors

Quick overview of most important highlights in the industry and on the site.

Like

More signal, less noise

Build your own feed by choosing topics you want to read about and editors you want to hear from.

Notifications

Stay up-to-date

Set up your notifications and don't miss out on content that matters to you

BT