Prerequisites
- Read this article about the processModel
- Read this article about ASP.NET Threads
- Read this article about Breaking Changes between Classic and Integrated mode
- See LAB 24: Deploy a Custom Module and Handler, Integrated mode support both Managed and Native Modules, once available
- Read this article about ASP.NET Page Events
- Read Contention, poor performance, deadlocks with ASP.NET here.
Setup
- Setup CSharpGuitarBugs website, as per Lab 1
Lab 7-1
Check max concurrent request limits
Figure 1, Integrated versus Classic mode
- Take a memory dump of CSharpGuitarBugs using one of this method after accessing an ASPX file or MVC route. Q: Why is taking a memory after accessing the ASPX file important? A: It is important because none of the binaries will be compiled into the process until there is a request made to it, learn more about this in Lab 3. I created the memory dump after clicking a few links on the web site, nothing particular.
Figure 2, Integrated versus Classic mode
- Open the memory dump in WinDbg and load the SOS.dll version corresponding to the .NET version which the web site is running in. For example, the one I used was C:\Windows\Microsoft.NET\Framework64\v4.0…\SOS.dll. I chose the Framework64 becuase my W3WP process is running in 64 bit mode.
Figure 3, Integrated versus Classic mode
- I know that the MaxWorkerThreads, RequestQueueLimit and MaxIoThreads propertires are contained within the System.Web.Configuration.ProcessModelSection class described here. The minFreeThreads and minLocalRequestFreeThreads are contained within the System.Web.Configuration.HttpRuntimeSection class described here. The maxConnection is contained in the System.Web.Configuration.ConnectionManagement class described here. Additional properties like MaxConcurrentRequestsPerCPU and MaxConcurrentThreadsPerCPU which are contained in the System.Web.Hosting.HostingEnvironment class described here. Historically, you could have used PSSCOR4.DTC to achieve about the same as dumping them all out manually, see here, but at the moment there are some issues with that, and doing it old school gives some better depth and understanding.
NOTE(1): I wrote another post about the HostingEnvironment class here, where you can look at the _shutDownReason to determine why an ASP.NET app is recycling. It might be worth a quick look.
NOTE(2): If you look at the source code for the MaxConcurrentRequestsPerCPU and MaxConcurrentThreadsPerCPU in the System.Web.Hosting.HostingEnvironment class here you will notice that it returns an UnsafeIISMethods.MgdGetMaxConcurrentThreadsPerCPU();. click on the MgdGetMaxConcurrentThreadsPerCPU() method and you find that it is calling a method with the same name via a DllImport on a non open source IIS module. What this means is that you will not be able to dump this without private symbols, I tested with the public ones and I was not able to dump them. You can also see in the code that those 2 properties are available in Integrated mode.
Let’s start by dumping out the RequestQueueLimit in the within the System.Web.Configuration.ProcessModelSection class see the source code here and notice it is stored in _propRequestQueueLimit
- .load \sos.dll
- !sos.dumpheap –type System.Web.Configuration.ProcessModelSection
- !do
Figure 4, Integrated versus Classic mode
- Although you cannot currently enter “dt webengine4!W3_MGD_REQUEST_QUEUE::***”, as mentioned above in NOTE(2) due to needing private symbols, I have done it to show the the value? Q: Why is the vale 30000? A: Because the default value is 5000 per CPU, because I am running on a 6 CPU machine (6 * 5000 = 30000).
Figure 5, Integrated versus Classic mode
- For the CSharpGuitarBugs web site, configure MaxConcurrentRequestsPerCPU in the system registry to 6000.
Figure 6, Integrated versus Classic mode
- Restart IIS and run the CSharpGuitarBugs and access a few pages, create a new memory dump.
a. Q: What does Restart IIS mean? A: Because I made a change to the registry I stopped/started HTTP, started W3SVC and manually restarted the application pool and the site via the portal.
- Enter “dt webengine4!W3_MGD_REQUEST_QUEUE::***”. Q: What would you expect the result to be, why? See #4 above.
Figure 7, Install
- The CSharpGuitarBugs website cannot run in Classic mode, however, as mentioned above, this setting is only available in Integrated mode.
Lab 7-2
Make the same configuration by modifying the aspnet.config file.
- The same modification can be made in the <system.web> in the associated aspnet.config for the corresponding ASP.NET version. See below table.
Version of .NET Framework | Location of Aspnet_regiis.exe file |
.NET Framework version 3.0, and version 3.5 (32-bit systems) | %windir%\Microsoft.NET\Framework\v2.0.50727 |
.NET Framework 3.0, and version 3.5 (64-bit systems) | %windir%\Microsoft.NET\Framework64\v2.0.50727 |
.NET Framework version 4 (32-bit systems) | %windir%\Microsoft.NET\Framework\v4.0.30319 |
.NET Framework version 4 (64-bit systems) | %windir%\Microsoft.NET\Framework64\v4.0.30319 |
10. Make the change as shown below to the aspnet.config associated to the .NET Framework version your application pool is running under.
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<system.web>
<applicationPool maxConcurrentRequestsPerCPU="7000" requestQueueLimit="9555" />
</system.web>
</configuration>
NOTE: The configuration in the aspnet.config file will override any registry value (can be set in registry for 3.5+ too) and will not be valid in Classic mode.
- Take another memory dump and look at both the requestQueueLimit and the maxConcurrentRequestsPerCPU (if possible).
Lab 7-3
Pipeline Integration
Important topic is when migrating to IIS 7+ from IIS 6, if you get errors check to see if it runs in Classic mode. If yes, it’s because of a breaking change in the pipeline. As IIS 6 has retired over a year ago this may not be of much value, however, to know what once was does sometimes provide better understanding of why we have what currently exists.
- IIS 6 has 2 pipeline
- Native Code – Filters
- Managed Code – ASP.NET
- IIS 7+ has a single pipeline
- IIS and ASP.NET authentication stages are integrated
- Cannot use both Forms and IWA, Basic
- Results of authentication are available only in PostAuthenticateRequest
- IIS and ASP.NET authentication stages are integrated
IIS Pipeline (example) | ASP.NET Pipeline (HttpApplication Events) |
BEGIN_REQUEST | BeginRequest |
AUTHENTICATE_REQUEST | AuthenticateRequest |
AUTHORIZE_REQUEST | AuthorizeRequest |
RESOLVE_REQUEST_CACHE | ResolveRequestCache |
MAP_REQUEST_HANDLER | AcquireRequestState |
… | … |
PRE_EXECUTE_REQUEST_HANDLER | |
EXECUTE_REQUEST_HANDLER | PreRequestHandlerExecute |
RELEASE_REQUEST_STATE | PostRequestHandlerExecute |
UPDATE_REQUEST_CACHE | ReleaseRequestState |
LOG_REQUEST | UpdateRequestCache |
END_REQUEST | EndRequest |
***In Classic Mode the ASP.NET pipeline is run within the EXECUTE_REQUEST_HANDLER IIS Event.
Page Lifecycle Events
Page_PreInit()
Figure 8, Pipeline Integration
- Dynamic Master/Theme pages
- Localization
- Dynamic Control Inclusion
Page_Init()
Figure 9, Pipeline Integration
- Set control properties
Page_InitComplete()
Figure 10, Pipeline Integration
- Include code which must be executed after initialization is complete
Page_PreLoad()
Figure 11, Pipeline Integration
- VIEWSTATE is loaded
Page_Load()
Figure 12, Pipeline Integration
- Created by default and is the most common place for the execution of custom code
Page_LoadComplete()
Figure 13, Pipeline Integration
- Validation
- All controls have been loaded
Page_PreRender()
Figure 14, Pipeline Integration
- Final content change before conversion to HTML and send to client
Page_SaveStateComplete()
Figure 15, Pipeline Integration
- VIEWSTATE complete
- No changes to content allowed/will not be sent
- Code which needs complete VIEWSTATE