In my previous blog post, I discussed a brief history about ASP.NET Webforms/MVC applications and its deployment to IIS. Then we took a look in the new framework ASP.NET Core which was introduced keeping in mind the performance and cross platform readiness. As performance was one of the key drivers, they introduced entity framework core and all thenew web server named Kestrel. You can read the blog post here.
Hosting ASP.NET Core Applications on IIS – A Detailed Look
We discussed about ASP.NET MVC Core 2.1 and discussed some internal details about its deployment on IIS as a reverse proxy (which is recommended), and also took a look on using Kestrel as an Edge Server. Although Kestrel is matured enough to be used as an Edge Server but still IIS is considered better option. We also saw, how ASP.NET Core requests are handled by IIS. We need to install the .NET Core Hosting bundle (download here) which adds a module named ASP.NET Core Module (ANCM). ANCM is responsible to route the asp.net core request to Kestrel.
With ASP.NET Core 2.2, Microsoft introduced In-process hosting. This model allows us to host the asp.net core 2.2 directly inside the worker process (w3wp.exe) which is similar to earlier ASP.NET version. Let’s take a pictorial view
We can see that there is no dotnet.exe is involved here in the second part. All the components ANCM, CoreCLR and application code are loaded in same worker process.
To use the latest feature, we need to install the latest 2.2 bundle (download here) which installs the upgraded version of ANCM also referred as ANCMv2. After installation, both the modules can be seen in IIS modules section as
Why new version of ASP.NET Core Module (ANCMv2)?
Earlier the idea with ANCM to use IIS as a reverse proxy and leverage Kestrel as a backend web server (as it was not hardened enough as an edge server) but as Kestrel got all the required enhancements, MS reworked on ANCM so that IIS can be used another platform to host asp.net core applications without the need of Kestrel. ANCM got redesigned and divided in two components, a shim and a request handler.
Shim – As the name suggests, it is a very light weight component which is continue to be installed as a global module via bundle which just work as an interface between IIS and request handler.
Request Handler – Request Handler is now an independent component which does all the work and can be updated via nuget. We can have multiple versions of request handler side by side. It means we can have multiple application using its own request handler.
With earlier ANCM, it was available as global singleton module which is shared by all the application which is a major bottleneck in releasing newer versions as it has to support every application. With the new architecture, we also get better process management, performance enhancements and easy updates via nuget.
We have so many benefits with the new model however we have one limitation – one application pool can only host only one application (In ASP.NET Web Form/MVC we could share app pools with multiple applications) as we don’t have the concept of Application domains in CoreCLR and this feature supports to CoreCLR only.
Let’s see an example
Now I have created another sample web application application using ASP.NET Core 2.2 (used VS 2017 v15.9.4) and deployed to IIS after publishing that.
There is no brainer here, let’s see the processes
Just to compare with earlier version I am adding both here.
So we can see the difference, in first scenario (<ASP.NET Core 2.2) the application is running under dotnet.exe while in second scenario, it is running under the worker process (w3wp.exe) itself which boosts the performance significantly as we don’t have to manage the dotnet process (earlier approach could have reliability issues as well) and request doesn’t have to travel outside of the process.
ASP.NET Core 2.2 allows out of process deployment as well. When we publish our application, it generates a web.config which has following xml node
<aspNetCore processPath=”dotnet” arguments=”.\InProcApp.dll” stdoutLogEnabled=”false” stdoutLogFile=”.\logs\stdout” hostingModel=”InProcess” />
Here hosting model at the end defined as InProcess. We can change it to OutOfProcess which would be similar as earlier one and application would be running using dotnet.exe. These configuration can also be set via Visual Studio while debugging as
Go to Solution Explorer -> Right Click on project-> Debug (tab)-> Web Server settings section
As mentioned above, with ASP.NET Core 2.2 allows us to host both the In-process and Out-of-process model (It is similar to earlier version). I have done sample load test using the Netling (know more about this tool here) and for out-of-process result is here
We can see that 2576 request got served per second. I changed the hosting as In-process and ran the same test again and the results are
Here we can see that request per second got increased significantly to 3742 which is approximate ~50% increase. Other data points like median, stddev also got reduced significantly. Itmay vary based on the scenario as I ran it on a developer VM and the application used was a default sample application using asp.net core 2.2 (not an empty application). However, Microsoft ran the test in performance labs where they got 4x throughput with In-process hosting.
Even kestrel was introduced with ASP.NET Core as a highly performant web server or as an alternate to IIS, it was always suggested to use IIS as frontend server in windows environment. Initially, many important features were missing in Kestrel which got added with the release of asp.net core 2.0 and 2.1, still IIS is advised to use for enterprise environment and internet facing application mainly due to security and stability reasons. There were several bottlenecks with having two different processes (w3wp.exe and dotnet.exe) and the way like port conflicts/not available, process management etc. All these can be avoided using In-process hosting model.