Editor note: This blog is originally published by Jose Reyes - ASP.NET on 02-29-2012 in Web Performance Blog, which will be obsolete soon. Future ASP.NET related performance blogs will be posted here.
Introduction
There is a file called aspnet.config in the .Net framework installation. This file is used to specify startup flags for both ASP.NET and CLR for those settings that are needed very early in the worker process lifetime, when the config system is not yet present.
In IIS 7.5 we added an attribute to the
There is another attribute on the
IIS 7.5 issue.
There was a problem in IIS 7.5, in which the managedRuntimeLoader was never provided with the path to this CLRConfigFile, so it was forced to use the one in the framework directory. So if you wanted to use the CLRConfigFile, to setup different CLR flags for an application pool, you will need to set the attribute AND explicitly clear the managedRuntimeLoader attribute on the application pool definition on applicationHost.config:
...
<system.applicationHost>
...
<applicationPools>
<addname="MyAppPool"CLRConfigFile="c:\myconfigs\myapp1\aspnet.config"managedRuntimeLoader="" />
...
The second step shouldn’t be necessary and is confusing. The clearing of the attributes basically forces the fall back to IIS runtime loader, which uses the correct CLRConfigFile.
This has been fixed on IIS 8, where you only need to set the CLRConfigFile attribute.
To verify this is working, you can change one parameter on the aspnet.config such as disabling the server garbage collector. (Note: Disabling the server garbage collector is a good thing if you want to save memory, at the expense of throughput. Typical use of this is hosting scenarios, where web sites has low traffic and higher site density is desirable.)
<configuration>
<runtime>
...
<gcServerenabled="false"/>
Attaching a debugger to the worker process and using SOS command !eeversion will show the garbage collector mode being used:
C:\>cdb.exe -pn w3wp.exe
Microsoft (R) Windows Debugger Version 6.13.0009.1140 X86
Copyright (c) Microsoft Corporation. All rights reserved.
…
0:044> .loadby sos clr
0:044> !eeversion
4.0.30319.239 retail
Workstation mode
SOS Version: 4.0.30319.239 retail build
Make sure your box has more than one logical core; otherwise workstation mode will always be used.
Implementing a loader
Implementing a loader is probably not needed, but if you want to do it, you will need a native DLL that exports a function named LoadManagedRuntime. In IIS 8 you can also export LoadManagedRuntimeEx. The function signature is shown below:
HRESULT __stdcall
LoadManagedRuntime(
_In_ PCWSTR pwszRuntimeVersion,
__deref_out IUnknown ** ppManagedRuntimeHost)
{
return LoadRuntimeInternal(pwszRuntimeVersion, ppManagedRuntimeHost);
}
HRESULT __stdcall
LoadManagedRuntimeEx(
_In_ PCWSTR pwszRuntimeVersion,
_In_ PCWSTR pszClrConfigFile,
__deref_out IUnknown ** ppManagedRuntimeHost)
{
return LoadRuntimeInternal(pwszRuntimeVersion, ppManagedRuntimeHost, pszClrConfigFile);
}
HRESULT LoadRuntimeInternal(_In_ PCWSTR pwszRuntimeVersion, __deref_out IUnknown** ppHost /*= NULL*/, _In_ PCWSTR pwszAspNetHostConfig /*= NULL*/) {
HMODULE hModule = NULL;
HRESULT hr = S_OK;
IUnknown *pHost = NULL;
PFNCorBindToRuntimeHost pCorBindToRuntimeHost;
TCHAR szPath[MAX_PATH + 1];
TCHAR szAspConfig[MAX_PATH + 1];
ExpandEnvironmentStrings(L"%windir%\\system32\\mscoree.dll", szPath, MAX_PATH);
if(pwszAspNetHostConfig == NULL) {
ExpandEnvironmentStrings(ASPNET_CONFIG, szAspConfig, MAX_PATH);
pwszAspNetHostConfig = szAspConfig;
}
hModule = LoadLibrary(szPath);
ON_NULL_EXIT(hModule);
pCorBindToRuntimeHost = (PFNCorBindToRuntimeHost)GetProcAddress(hModule, "CorBindToRuntimeHost");
ON_NULL_EXIT(pCorBindToRuntimeHost);
hr = pCorBindToRuntimeHost(
L"v4.0.30319",
L"svr",
pwszAspNetHostConfig,
NULL, // reserved
STARTUP_CONCURRENT_GC|STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST|STARTUP_LOADER_SAFEMODE|STARTUP_DISABLE_COMMITTHREADSTACK|STARTUP_HOARD_GC_VM,
CLSID_CLRRuntimeHost,
IID_IUnknown,
(VOID**)&pHost);
Cleanup:
if (pHost != NULL && ppHost != NULL) {
pHost->AddRef();
*ppHost = pHost;
}
if(hModule != NULL) {
FreeLibrary(hModule);
}
return hr;
}
See the attached project for the full sample code. The sample can be compiled into a native DLL and the managedRuntimeLoader attribute can be set to point to that DLL.
...
<system.applicationHost>
...
<applicationPools>
<addname="MyAppPool"CLRConfigFile="c:\myconfigs\myapp1\aspnet.config"managedRuntimeLoader="c:\mynativedlls\myruntimeloader.dll" />
...
Note that debugging such a code on IIS will require the use of “Image File Execution Options”, since the code is executed very early on the worker process lifecycle. An easier way to test might be to load the library yourself and call the functions, the way IIS would (see the test project).
Conclusion
IIS 7.5 required for you to clean the managedRuntimeLoader attribute, if you wanted to change CLR parameters on your own CLRConfigFile.
Implementation of a managed runtime loader requires a native DLL which exports a LoadManagedRuntime() and/or LoadManagedRuntimeEx().
Thanks for reading.
Originally posted at http://blogs.msdn.com/b/josere/