'ASP.NET Core 6.0+: How to get the current (case-sensitive) IIS Website Name?
I'm trying to get the name of my ASP.NET 6 app hosted in IIS. What I need is exactly this name with proper casing:
In .NET Framework 4.8, this name was provided by HttpRequest.ApplicationPath and it was returned with proper casing (as configured in IIS, not as in the coming request's URL). However, it doesn't exist in .NET 6.
I tried:
HttpContext.Request.PathBase, but it returns the path exactly as in the requesting URL, not as in the IIS- injecting
IServerAddressesFeatureandIWebHostEnvironment, but none of them contains the name from IIS with correct casing IServerAddressesFeature, but also didn't find anything relevant here- getting server variables:
IServerVariablesFeature serverVars = HttpContext.Features.Get<IServerVariablesFeature>()and then the IIS Site name:string iis_version = serverVars["INSTANCE_NAME"](see documentation here), but it returns the app name in capital letters (MYSITE.WEB)
Does anyone know how to get this site's name as configured in IIS (with proper casing)?
Solution 1:[1]
TL;DR:
- Use the
APPL_MD_PATHserver-variable.- This contains the IIS Metabase Application Path string. (AFAIK, "MD" stands for "Meta-database").
- Quoteth the docs:
https://docs.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms524602(v=vs.90)?redirectedfrom=MSDN
"
APPL_MD_PATH- Retrieves the metabase path of the application."
Like so:
// This code assumes HttpContext is available, such as in a Middleware method or `Controller` subclass.
using Microsoft.AspNetCore.Http;
String? iisMetabasePath = httpContext.GetServerVariable("APPL_MD_PATH");
// or (long-form):
String? iisMetabasePath = HttpContextServerVariableExtensions.GetServerVariable( httpContext, "APPL_MD_PATH" );
Then just trim-off the /LM/W3SVC/ part.
Note that when you run your code outside of IIS, such as with ASP.NET Core's development server, all IIS-specific data, like "APPL_MD_PATH" won't be available, so make sure you're handling that case too.
Original research: What happened to ApplicationRoot?
Time to bust-out ILSpy...
HttpRequest.ApplicationPathisHttpRuntime.AppDomainAppVirtualPath.HttpRuntime.AppDomainAppVirtualPathisVirtualPath.GetVirtualPathStringNoTrailingSlash(HttpRuntime._theRuntime._appDomainAppVPath).HttpRuntime._theRuntime._appDomainAppVPathis set inHttpRuntime.Init().HttpRuntime.Init()sets_appDomainAppVPathfromHttpRuntime.GetAppDomainString(".appVPath")).- "AppDomain Strings" are small serializable scalar values that are associated with each
AppDomain. - Generally speaking, ASP.NET in .NET Framework (aka
System.Web) creates a newAppDomainfor each Application Scope in IIS. - And of course, AppDomains no-longer exist in .NET Core and later.
- So let's find out where the
Stringvalue for".appVPath"comes from...
- "AppDomain Strings" are small serializable scalar values that are associated with each
System.Web.Hosting.ApplicationManager::PopulateDomainBindingssetsdict.Add(".appVPath", appVPath.VirtualPathString)- "domain bindings" in this context refers to AppDomain bindings: nothing at all to do with DNS domain-names or
Hostheader bindings in IIS. Yay for overloaded terminology.
- "domain bindings" in this context refers to AppDomain bindings: nothing at all to do with DNS domain-names or
PopulateDomainBindingsis called bySystem.Web.Hosting.ApplicationManager::CreateAppDomainWithHostingEnvironment.- And it gets
virtualPath: VirtualPath.Create(appHost.GetVirtualPath()).
- And it gets
appHost.GetVirtualPath()isIApplicationHost.GetVirtualPath().- There are 2 in-box implementations:
System.Web.Hosting.ISAPIApplicationHostandSystem.Web.Hosting.SimpleApplicationHost. We're interested inISAPIApplicationHost.
- There are 2 in-box implementations:
ISAPIApplicationHostgets its virtualPath from the runtime argument toString appIdandString appPathin theIAppManagerAppDomainFactory.Createmethod.- And
IAppManagerAppDomainFactoryis a COM interface used directly by IIS.- The plot thickens...
- And
- At this point I got lost trawling through the legacy IIS 6 ISAPI documentation, looking for traces of the original COM definition of
IAppManagerAppDomainFactorybut came up empty-handed.- It's probably handled by
webengine4.dllwhich is a native DLL and I don't have the time to bust-out Ghidra right now... - I did notice that the ISAPI request entrypoint method
HttpExtensionProc(and itsLPEXTENSION_CONTROL_BLOCKparameter) do not contain the IIS Application ScopeAppIdor Virtual Path, which surprised me - but most importantly: this suggests the value must likely come from theGetServerVariableorServerSupportFunctioncallbacks.... - However that's likely a waste of time anyway IIS 6 is not IIS7+ and IIS7+'s interfaces are no-longer called "ISAPI" but instead called just "IIS Native-Code API" (that's the most plain and boring API name I've seen in a while...).
- It's probably handled by
- So, starting with the "IIS Native-Code API" documentation I quickly found the
IWpfApplicationInfoUtil::GetApplicationPropertiesFromAppIdmethod (here "WPF" means "Worker Process Framework", and is entirely unrelated to the other UI-related WPF).- I also found the same data exposed via the
IMetadataInfo.GetMetaPath()method (which returns a string of the form"LM/WEBROOT/AppHost/{SiteId}"). - So how does an application get a
IWpfApplicationInfoUtilinterface reference?IWorkerProcessFramework->GetWpfInterface(WPF_APPLICATION_INFO_UTIL_ID)->GetApplicationPropertiesFromAppId- So how do you get
IWorkerProcessFramework?- It's passed as a parameter into your
w3wp.exeworker DLL. - So let's see what
AspNetCoreModuleV2does...
- It's passed as a parameter into your
- So how do you get
- I also found the same data exposed via the
- Actually
AspNetCoreModuleV2uses IIS'sIHttpApplication, derp.IHttpApplicationexposesGetAppConfigPath()which also returns a string of the form/LM/W3SVC/1/ROOT/{Site Name}.- ASP.NET Core seems to use it in a few places.
- At this point I gave up as it's now 6:20am, but that was a fun dive!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Dai |

