Generating a Hang Dump for ASP.NET Core app
At work I spend a great deal of time reviewing hang dumps for a variety of our web platforms, I am usually trying to figure out exactly how this app got into a one in a million state that has slowed the app, caused a CPU spike or excessive memory consumption. Now that I am working on DasBlog Core in my spare time I have been forced to look at a couple of really bizarre scenarios related to ASP.NET Core architecture. I will blog about those scenarios soon but for now I just wanted to take a quick look at the difference between ASP.NET (System.Web) vs ASP.NET Core when it comes to hang dumps.
Taking a hang dump
Normally when taking a web hang dump we use task manager (or IIS) to identify a specific IIS worker process (w3wp) because our app is running inside this context. I would then use Task Manager to right click on the process and Create dump file. Fairly straightforward, but this is slightly different for ASP.NET Core and to show that difference I point you to following image where I am using KUDU on Azure to identify the processes running in the cloud (but the principle applies to Task Manager).
Notice that I now have an IIS worker process and a dotnet.exe and our code is evidently in the dotnet process (PID 9908), and this is the process from which I would need to take the hang dump. This is an important difference from classic ASP.NET web app.
ASP.NET Core Module (IIS)
A new module was developed for IIS, the ASP.NET Core Module, and it allows ASP.NET Core apps to run behind IIS in a reverse proxy configuration, this allows the venerable and versatile IIS to continue to provide world class security and configurability.
As noted the ASP.NET Core apps run in a process separate from the IIS worker process, I grabbed this diagram from Microsoft docs that helps illustrate the new architecture.
So let’s consider all the steps as soon as it hits the web server:-
- HTTP.sys driver routes the requests to IIS (usually via port 80 HTTP, 443 HTTPs)
- The module forwards all request via HTTP to Kestrel on a different port (not 80 or 443 as they are in use)
- Requests not forwarded via the module are rejected
- The request is pushed into the ASP.NET Core middleware pipeline
- The middleware pipeline manages the request and creates a HttpContext instance for your app (this is where routing does its magic)
This is not an insignificant change and with the conversion of DasBlog I ran into a couple issues that are rooted in this architectural difference and I will talk about them soon.