Setting an aspnet.config File per Application Pool
The aspnet.config file is a little known config file which is supported by ASP.NET 2.0 and greater. Generally it lives in the root of the framework folder, for example:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet.config
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\aspnet.config
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet.config
This config file is further leveraged in ASP.NET 4.0 for concurrency and threading. For example, you can set maxConcurrentRequestsPerCPU, maxConcurrentThreadsPerCPU and requestQueueLimit, in addition to the previous runtime settings.
In Windows Server 2008 R2 (IIS 7.5) support was added to allow different settings per application pool. Where previously the settings had to be applied to the whole framework version, now they can be specific to each app pool. It does this by allowing you to create a custom aspnet.config file per app pool. You can save them wherever you want on disk and IIS will pick them up when the app pool starts.
This is supported by a new attribute for the IIS app pool called CLRConfigFile mentioned in this MSDN article. There is no default value which means that if you don’t set it, it will read the framework’s aspnet.config file and not look for additional files.
It doesn’t appear to be configurable from the application pool settings in IIS Manager so you must use any of the manual ways to set it. appcmd is probably the easiest. Here’s what it will look like, notice the two variables are the path and the application pool name:
%windir%\System32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools /[name='DefaultAppPool'].CLRConfigFile:"c:\inetpub\AppPoolClrConfig\DefaultAppPool_aspnet.config" /commit:apphost
Below is another copy of the same, but as a template. Just swap out the {AppPoolName} and {FilePath} with your settings. (run appcmd from %windir%\System32\inetsrv)
appcmd.exe set config -section:system.applicationHost/applicationPools /[name='{AppPoolName}'].CLRConfigFile:"{FilePath}" /commit:apphost
Note that the framework aspnet.config file is still used so only differences per app pool need to be set here.
Here’s an example of what the file can contain:
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="false" />
<legacyImpersonationPolicy enabled="true"/>
<alwaysFlowImpersonationPolicy enabled="false"/>
<SymbolReadingPolicy enabled="1" />
<shadowCopyVerifyByTimestamp enabled="true"/>
</runtime>
<startup useLegacyV2RuntimeActivationPolicy="true" />
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="5000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="5000" />
</system.web>
</configuration>
As for disk permissions, the app pool will try to read the file using the app pool’s identity. Since this file is probably not a security risk you can grant Users with read permissions and it will work. Alternately, you can properly lock down the file like so:
icacls c:\inetpub\AppPoolClrConfig\DefaultWebSite_aspnet.config /grant "IIS APPPOOL\DefaultAppPool":(R)
Be sure that the file doesn’t have inheritance or other more permissive permissions already set.
Now you can make adjustments per app pool in each of the corresponding config files, and it’s also fine to point multiple app pools to the same config file.
Changes are picked up when the app pool is created, so after applying any changes be sure to recycle the app pool.
Note also that this is for IIS 7.5 and greater, and the applicationPool settings only apply in Integrated Pipeline mode.
Here are some good links with further reading:
- <system.web> applicationPool settings: http://msdn.microsoft.com/en-us/library/dd560842.aspx
- ASP.NET Thread Usage article: http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
- applicationPools config settings in IIS 7.5: http://msdn.microsoft.com/en-us/library/aa347554(VS.90).aspx