Skip to content

Commit 1fede09

Browse files
[release/8.0] Add feature to expose IIS hosting details (#50443)
1 parent cc062bb commit 1fede09

File tree

15 files changed

+300
-7
lines changed

15 files changed

+300
-7
lines changed

src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/AspNetCore.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<ClInclude Include="AppOfflineApplication.h" />
3636
<ClInclude Include="AppOfflineHandler.h" />
3737
<ClInclude Include="DisconnectHandler.h" />
38+
<ClInclude Include="ModuleEnvironment.h" />
3839
<ClInclude Include="ShimOptions.h" />
3940
<ClInclude Include="globalmodule.h" />
4041
<ClInclude Include="resource.h" />
@@ -49,6 +50,7 @@
4950
<ClCompile Include="AppOfflineApplication.cpp" />
5051
<ClCompile Include="AppOfflineHandler.cpp" />
5152
<ClCompile Include="DisconnectHandler.cpp" />
53+
<ClCompile Include="ModuleEnvironment.cpp" />
5254
<ClCompile Include="ShimOptions.cpp" />
5355
<ClCompile Include="dllmain.cpp" />
5456
<ClCompile Include="globalmodule.cpp" />
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
#include "ModuleEnvironment.h"
5+
#include <string>
6+
#include <sstream>
7+
8+
// Set in the RegisterModule call IIS uses to initiate the module
9+
extern DWORD g_dwIISServerVersion;
10+
11+
static std::wstring GetIISVersion() {
12+
int major = (int)(g_dwIISServerVersion >> 16);
13+
int minor = (int)(g_dwIISServerVersion & 0xffff);
14+
15+
std::wstringstream version;
16+
version << major << "." << minor;
17+
18+
return version.str();
19+
}
20+
21+
static std::wstring ToVirtualPath(const std::wstring& configurationPath) {
22+
int segments = 0;
23+
size_t position = configurationPath.find('/');
24+
25+
// Skip first 4 segments of config path
26+
while (segments != 3 && position != std::wstring::npos)
27+
{
28+
segments++;
29+
position = configurationPath.find('/', position + 1);
30+
}
31+
32+
if (position != std::wstring::npos)
33+
{
34+
return configurationPath.substr(position);
35+
}
36+
37+
return L"/";
38+
}
39+
40+
void SetApplicationEnvironmentVariables(_In_ IHttpServer &server, _In_ IHttpContext &pHttpContext) {
41+
SetEnvironmentVariable(L"ASPNETCORE_IIS_VERSION", GetIISVersion().c_str());
42+
43+
SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_ID", server.GetAppPoolName());
44+
45+
IHttpServer2* server2;
46+
if (SUCCEEDED(HttpGetExtendedInterface(&server, &server, &server2))) {
47+
SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_POOL_CONFIG_FILE", server2->GetAppPoolConfigFile());
48+
}
49+
50+
IHttpSite* site = pHttpContext.GetSite();
51+
SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_NAME", site->GetSiteName());
52+
SetEnvironmentVariable(L"ASPNETCORE_IIS_SITE_ID", std::to_wstring(site->GetSiteId()).c_str());
53+
54+
IHttpApplication* app = pHttpContext.GetApplication();
55+
SetEnvironmentVariable(L"ASPNETCORE_IIS_APP_CONFIG_PATH", app->GetAppConfigPath());
56+
SetEnvironmentVariable(L"ASPNETCORE_IIS_APPLICATION_ID", app->GetApplicationId());
57+
SetEnvironmentVariable(L"ASPNETCORE_IIS_APPLICATION_VIRTUAL_PATH", ToVirtualPath(app->GetAppConfigPath()).c_str());
58+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
#pragma once
5+
6+
void SetApplicationEnvironmentVariables(_In_ IHttpServer& server, _In_ IHttpContext& pHttpContext);

src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationinfo.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "ConfigurationLoadException.h"
1717
#include "resource.h"
1818
#include "file_utility.h"
19+
#include "ModuleEnvironment.h"
1920

2021
extern HINSTANCE g_hServerModule;
2122
extern BOOL g_fInAppOfflineShutdown;
@@ -72,6 +73,8 @@ APPLICATION_INFO::CreateHandler(
7273
HRESULT
7374
APPLICATION_INFO::CreateApplication(IHttpContext& pHttpContext)
7475
{
76+
SetApplicationEnvironmentVariables(m_pServer, pHttpContext);
77+
7578
auto& pHttpApplication = *pHttpContext.GetApplication();
7679
if (AppOfflineApplication::ShouldBeStarted(pHttpApplication))
7780
{

src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ BOOL g_fRecycleProcessCalled = FALSE;
1919
BOOL g_fInShutdown = FALSE;
2020
BOOL g_fInAppOfflineShutdown = FALSE;
2121
HINSTANCE g_hServerModule;
22+
DWORD g_dwIISServerVersion;
2223

2324
VOID
2425
StaticCleanup()
@@ -90,7 +91,7 @@ HRESULT
9091
9192
--*/
9293
{
93-
UNREFERENCED_PARAMETER(dwServerVersion);
94+
g_dwIISServerVersion = dwServerVersion;
9495

9596
if (pHttpServer->IsCommandLineLaunch())
9697
{

src/Servers/IIS/IIS/samples/NativeIISSample/Startup.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,32 @@ public void Configure(IApplicationBuilder app)
9696
}
9797

9898
await context.Response.WriteAsync(Environment.NewLine);
99-
var addresses = context.RequestServices.GetService<IServer>().Features.Get<IServerAddressesFeature>();
99+
var server = context.RequestServices.GetService<IServer>();
100+
101+
var addresses = server.Features.Get<IServerAddressesFeature>();
100102
foreach (var key in addresses.Addresses)
101103
{
102104
await context.Response.WriteAsync(key + Environment.NewLine);
103105
}
106+
107+
if (server.Features.Get<IIISEnvironmentFeature>() is { } envFeature)
108+
{
109+
await context.Response.WriteAsync(Environment.NewLine);
110+
await context.Response.WriteAsync("IIS Environment Information:" + Environment.NewLine);
111+
await context.Response.WriteAsync("IIS Version: " + envFeature.IISVersion + Environment.NewLine);
112+
await context.Response.WriteAsync("ApplicationId: " + envFeature.ApplicationId + Environment.NewLine);
113+
await context.Response.WriteAsync("Application Path: " + envFeature.ApplicationPhysicalPath + Environment.NewLine);
114+
await context.Response.WriteAsync("Application Virtual Path: " + envFeature.ApplicationVirtualPath + Environment.NewLine);
115+
await context.Response.WriteAsync("Application Config Path: " + envFeature.AppConfigPath + Environment.NewLine);
116+
await context.Response.WriteAsync("AppPool ID: " + envFeature.AppPoolId + Environment.NewLine);
117+
await context.Response.WriteAsync("AppPool Config File: " + envFeature.AppPoolConfigFile + Environment.NewLine);
118+
await context.Response.WriteAsync("Site ID: " + envFeature.SiteId + Environment.NewLine);
119+
await context.Response.WriteAsync("Site Name: " + envFeature.SiteName + Environment.NewLine);
120+
}
121+
else
122+
{
123+
await context.Response.WriteAsync($"No {nameof(IIISEnvironmentFeature)} available." + Environment.NewLine);
124+
}
104125
});
105126
}
106127

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using Microsoft.Extensions.Configuration;
6+
7+
namespace Microsoft.AspNetCore.Server.IIS.Core;
8+
9+
internal sealed class IISEnvironmentFeature : IIISEnvironmentFeature
10+
{
11+
public static bool TryCreate(IConfiguration configuration, [NotNullWhen(true)] out IIISEnvironmentFeature? result)
12+
{
13+
var feature = new IISEnvironmentFeature(configuration);
14+
15+
if (feature.IISVersion is not null)
16+
{
17+
result = feature;
18+
return true;
19+
}
20+
21+
result = null;
22+
return false;
23+
}
24+
25+
private IISEnvironmentFeature(IConfiguration configuration)
26+
{
27+
if (Version.TryParse(configuration["IIS_VERSION"], out var version))
28+
{
29+
IISVersion = version;
30+
}
31+
32+
if (uint.TryParse(configuration["IIS_SITE_ID"], out var siteId))
33+
{
34+
SiteId = siteId;
35+
}
36+
37+
AppPoolId = configuration["IIS_APP_POOL_ID"] ?? string.Empty;
38+
AppPoolConfigFile = configuration["IIS_APP_POOL_CONFIG_FILE"] ?? string.Empty;
39+
AppConfigPath = configuration["IIS_APP_CONFIG_PATH"] ?? string.Empty;
40+
ApplicationPhysicalPath = configuration["IIS_PHYSICAL_PATH"] ?? string.Empty;
41+
ApplicationVirtualPath = configuration["IIS_APPLICATION_VIRTUAL_PATH"] ?? string.Empty;
42+
ApplicationId = configuration["IIS_APPLICATION_ID"] ?? string.Empty;
43+
SiteName = configuration["IIS_SITE_NAME"] ?? string.Empty;
44+
}
45+
46+
public Version IISVersion { get; } = null!;
47+
48+
public string AppPoolId { get; }
49+
50+
public string AppPoolConfigFile { get; }
51+
52+
public string AppConfigPath { get; }
53+
54+
public string ApplicationPhysicalPath { get; }
55+
56+
public string ApplicationVirtualPath { get; }
57+
58+
public string ApplicationId { get; }
59+
60+
public string SiteName { get; }
61+
62+
public uint SiteId { get; }
63+
}

src/Servers/IIS/IIS/src/Core/IISHttpServer.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.AspNetCore.Hosting.Server;
1010
using Microsoft.AspNetCore.Hosting.Server.Features;
1111
using Microsoft.AspNetCore.Http.Features;
12+
using Microsoft.Extensions.Configuration;
1213
using Microsoft.Extensions.Hosting;
1314
using Microsoft.Extensions.Logging;
1415
using Microsoft.Extensions.Options;
@@ -58,6 +59,7 @@ public IISHttpServer(
5859
IISNativeApplication nativeApplication,
5960
IHostApplicationLifetime applicationLifetime,
6061
IAuthenticationSchemeProvider authentication,
62+
IConfiguration configuration,
6163
IOptions<IISServerOptions> options,
6264
ILogger<IISHttpServer> logger
6365
)
@@ -77,6 +79,11 @@ ILogger<IISHttpServer> logger
7779

7880
Features.Set<IServerAddressesFeature>(_serverAddressesFeature);
7981

82+
if (IISEnvironmentFeature.TryCreate(configuration, out var iisEnvFeature))
83+
{
84+
Features.Set<IIISEnvironmentFeature>(iisEnvFeature);
85+
}
86+
8087
if (_options.MaxRequestBodySize > _options.IisMaxRequestSizeLimit)
8188
{
8289
_logger.LogWarning(CoreStrings.MaxRequestLimitWarning);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.AspNetCore.Server.IIS;
5+
6+
/// <summary>
7+
/// This feature provides access to IIS application information
8+
/// </summary>
9+
public interface IIISEnvironmentFeature
10+
{
11+
/// <summary>
12+
/// Gets the version of IIS that is being used.
13+
/// </summary>
14+
Version IISVersion { get; }
15+
16+
/// <summary>
17+
/// Gets the AppPool name that is currently running
18+
/// </summary>
19+
string AppPoolId { get; }
20+
21+
/// <summary>
22+
/// Gets the path to the AppPool config
23+
/// </summary>
24+
string AppPoolConfigFile { get; }
25+
26+
/// <summary>
27+
/// Gets path to the application configuration that is currently running
28+
/// </summary>
29+
string AppConfigPath { get; }
30+
31+
/// <summary>
32+
/// Gets the physical path of the application.
33+
/// </summary>
34+
string ApplicationPhysicalPath { get; }
35+
36+
/// <summary>
37+
/// Gets the virtual path of the application.
38+
/// </summary>
39+
string ApplicationVirtualPath { get; }
40+
41+
/// <summary>
42+
/// Gets ID of the current application.
43+
/// </summary>
44+
string ApplicationId { get; }
45+
46+
/// <summary>
47+
/// Gets the name of the current site.
48+
/// </summary>
49+
string SiteName { get; }
50+
51+
/// <summary>
52+
/// Gets the id of the current site.
53+
/// </summary>
54+
uint SiteId { get; }
55+
}

src/Servers/IIS/IIS/src/PublicAPI.Unshipped.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,14 @@
2626
*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.ReadTimeout.get -> int
2727
*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.ReadTimeout.set -> void
2828
*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.Seek(long offset, System.IO.SeekOrigin origin) -> long
29-
*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.SetLength(long value) -> void
29+
*REMOVED*override Microsoft.AspNetCore.Server.IIS.Core.WriteOnlyStream.SetLength(long value) -> void
30+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature
31+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppConfigPath.get -> string!
32+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationId.get -> string!
33+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationPhysicalPath.get -> string!
34+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.ApplicationVirtualPath.get -> string!
35+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolConfigFile.get -> string!
36+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.AppPoolId.get -> string!
37+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.IISVersion.get -> System.Version!
38+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteId.get -> uint
39+
Microsoft.AspNetCore.Server.IIS.IIISEnvironmentFeature.SiteName.get -> string!

0 commit comments

Comments
 (0)