Home > Software design >  ASP.NET 6: get case-sensitive IIS site name
ASP.NET 6: get case-sensitive IIS site name

Time:03-31

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:

enter image description here

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 IServerAddressesFeature and IWebHostEnvironment, 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)?

CodePudding user response:

TL;DR:

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...

  1. HttpRequest.ApplicationPath is HttpRuntime.AppDomainAppVirtualPath.
  2. HttpRuntime.AppDomainAppVirtualPath is VirtualPath.GetVirtualPathStringNoTrailingSlash(HttpRuntime._theRuntime._appDomainAppVPath).
  3. HttpRuntime._theRuntime._appDomainAppVPath is set in HttpRuntime.Init().
  4. HttpRuntime.Init() sets _appDomainAppVPath from HttpRuntime.GetAppDomainString(".appVPath")).
  5. System.Web.Hosting.ApplicationManager::PopulateDomainBindings sets dict.Add(".appVPath", appVPath.VirtualPathString)
    • "domain bindings" in this context refers to AppDomain bindings: nothing at all to do with DNS domain-names or Host header bindings in IIS. Yay for overloaded terminology.
  6. PopulateDomainBindings is called by System.Web.Hosting.ApplicationManager::CreateAppDomainWithHostingEnvironment.
    • And it gets virtualPath: VirtualPath.Create(appHost.GetVirtualPath()).
  7. appHost.GetVirtualPath() is IApplicationHost.GetVirtualPath().
    • There are 2 in-box implementations: System.Web.Hosting.ISAPIApplicationHost and System.Web.Hosting.SimpleApplicationHost. We're interested in ISAPIApplicationHost.
  8. ISAPIApplicationHost gets its virtualPath from the runtime argument to String appId and String appPath in the IAppManagerAppDomainFactory.Create method.
    • And IAppManagerAppDomainFactory is a COM interface used directly by IIS.
      • The plot thickens...
  9. At this point I got lost trawling through the legacy IIS 6 ISAPI documentation, looking for traces of the original COM definition of IAppManagerAppDomainFactory but came up empty-handed.
    • It's probably handled by webengine4.dll which 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 its LPEXTENSION_CONTROL_BLOCK parameter) do not contain the IIS Application Scope AppId or Virtual Path, which surprised me - but most importantly: this suggests the value must likely come from the GetServerVariable or ServerSupportFunction callbacks....
    • 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...).
  10. So, starting with the "IIS Native-Code API" documentation I quickly found the IWpfApplicationInfoUtil::GetApplicationPropertiesFromAppId method (here "WPF" means "Worker Process Framework", and is entirely unrelated to the other UI-related WPF).
  11. Actually AspNetCoreModuleV2 uses IIS's IHttpApplication, derp.
  12. At this point I gave up as it's now 6:20am, but that was a fun dive!
  • Related