This is Part 1 of a 3 part series on the ASP.NET Core Request Pipeline. Check back here for links to the follow-up articles!
- Part I - Receiving Requests
- Part II - Coming Soon
- Part III - Coming Soon
For many developers the area between a browser request and a controller action is a land a of mystery and magic. Any why shouldn't it be? In MVC/WebAPI and ASP.NET Core convention is king when it comes to routing and controllers. As long your naming scheme follows convention, you can safely expect requests to magically hit your code.
But what happens when you don't follow convention? Or when you need to support a more complex configuration that is not provided by out-of-the-box project templates? Don't be afraid, the request pipeline doesn't have to be a black box. And having a solid understanding of the request pipeline can take you from zero to hero by the end of the sprint.
In this article I break down of each type of server implementation and outline their differences. Check out the
tl;dr table at the end for a quick summary. After that I outline some common scenarios and which implementation is best suited for the job.
When it comes to web apps, something must be listening on a port (typically 80 or 443) to receive the request. Listening for and maintaining connections to requests are the primary responsibilities of a web server. When it comes to ASP.NET Core, there are a few implementations and hosting models that each have their own benefits.
Kestrel is the light-weight, cross-platform web server built specifically for ASP.NET Core. It's open source, can easily exceed 1M+ practical requests per second, and is the default when starting a new project for ASP.NET Core 3. Kestrel will listen on the specified hosts/ports and runs right within your web app.
Once connections are made, the requests are handled directly by the request pipeline. It's a great option to use for new projects since there are no additional dependencies and, even better, it works on Windows, Mac, AND Linux! I highly recommend using Kestrel during development and for open source projects.
When building enterprise server applications that run on Windows, you almost always will rely on the de facto web server: IIS. Originally released for Windows NT and rewritten for Windows Server 2008, it's currently on version 10 and provides stability, security, and management tools for production applications. To say that IIS has been battle tested is a massive understatement. And any enterprise developer/IT professional has probably relied on IIS at some point in there career.
IIS Out-of-Process hosting uses IIS as a reverse proxy that forwards requests to your ASP.NET Core app running on Kestrel (thanks to the ASP.NET Core Module). The primary benefit to this setup is the ability to host and configure a mix of .NET Framework and .NET Core apps. This simplifies configuration for things like SSL, caching, and authentication since they can be shared across applications.
Other reverse proxies can also be used (Apache for Windows/Linux, and Nginx for Linux). While they do provide support for other platforms, IIS provides dedicated support which will result in the best experience.
Starting with ASP.NET Core 2.2 if you app targets .NET Core (not the full .NET Framework) then you can take advantage of in-process hosting. This means that the IIS worker process (
w3wp.exe) actually loads up the CoreCLR and your ASP.NET Core app in the same process. This enables faster time to first byte by allowing requests to be passed directly into the pipeline!
This is improved performance does come at a cost. Only one application can be used per IIS Application Pool and there is no support for .NET Framework. But the benefit is 2x-3x improved requests per second.
HTTP.sys is a Windows-only web server focused on security and additional features (compared to Kestrel). Prior to ASP.NET Core 2.0, Kestrel was not secure enough to expose directly to the public internet. HTTP.sys allowed apps to be accessible on the public web without the need for IIS. Additionally it provides a few features not available to Kestrel, such as Windows Authentication.
Custom servers can be used in the off chance that a feature is not supported in Kestrel/IIS or HTTP.sys. Conforming to the Open Web Interface for .NET (OWIN), these servers implement a set of interfaces used to manage and interact with ASP.NET Core apps. You can learn about the
IServer interface and how to implement it here.
|In-process with IIS||Maximum Performance, but for Windows only.|
|Kestrel (standalone)||Lightweight and cross-platform.|
|Out of process IIS with Kestrel||Host alongside existing .NET Framework apps.|
|HTTP.sys||Advanced features, Windows only.|
|Custom OWIN Server||Complete control, highest complexity.|
The following scenarios are just a few possible cases to consider. Your specific project might have special circumstances or specific requirements from your organization.
Kestrel (standalone) is probably your best bet. The two main benefits for open source projects is cross-platform support and super simple workflow ( no messing with IIS Express ). While cross-platform is not a requirement for open source projects, there is nothing more annoying than finding a good project that doesn't have support for your platform. Now a simple developer workflow is something that we should all strive for, but not always obtainable. Regardless using standalone Kestrel is without a doubt the best option for new open source projects.
In most enterprise scenarios, legacy applications must be considered when building new applications. Some companies/administrators have strict rules on how sites get hosted. IIS can easily host new and legacy apps together, but you have to consider 2 things.
- If performance (speed and memory usage) are important, then In-Process with IIS is the way to go. By letting IIS load and execute the ASP.NET Core application, reverse proxy HTTP calls are avoided and request data is shared in memory. This results is faster response times and reduced memory consumption.
- If sharing AppPools is important, then use Out-Of-Process with IIS. IIS will act like a reverse proxy, which allows you to share AppPools between legacy apps and new apps. Your ASP.NET Core app will have a Kestrel server running, but will be completely managed by IIS. While this does slow down the request speed, it does provided benefits around shared security, availability , etc.
For brand new projects, Kestrel (standalone) is your best place to start. Kestrel provides a lightweight server for easy development, allowing your team to spend more time focusing on building the app. If you are developing for Windows-only and using IIS, then consider deploying with IIS In-Process. In addition to an easier configuration, you will find less memory usage and faster response time.
If you need to squeeze every ounce of performance out of your tech stack, then believe it or not but Kestrel (standalone) is probably your best bet. The ASP.NET team has put in a tremendous amount of effort to make Kestrel a top tier web server when it comes to requests per second. The key to keeping your server performant is through the use of custom middleware instead of the "general use" implementations used by most projects. Kestrel, when stripped down to simple text-based requests, can handle about 6 MILLION requests per second. With some smart authentication and body parsing optimized for your domain, you would be surprised at how fast Kestrel can fly.
Without a doubt the first server to try is Kestrel (standalone). With complete security implementation (ASP.NET Core 2.0 and beyond) and a highly dedicated team pushing its performance to the max, most projects will be perfectly happy relying on Kestrel. The best part is that you can use standalone Kestrel during development and deploy with IIS In-Process or Out-of-Process with just a few configuration changes.
All projects, big or small, benefit when starting off on the right foot. Plan ahead and learn about the options you have available when it comes to project architecture. The most difficult projects don't always have the most complex logic; they have the least amount of high-level planning.
Keep an eye out for Part 2 of this series on the ASP.NET Core Request Pipeline. It will dive into the details of pipeline configuration and MVC middleware!
Questions? Comments? Disagreements? Hit me up on Twitter!