diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp index fa1282cdb6..208d4a1eaa 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp @@ -43,11 +43,17 @@ ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) : m_struStdoutLogFile = section->GetRequiredString(CS_ASPNETCORE_STDOUT_LOG_FILE); m_fDisableStartupPage = section->GetRequiredBool(CS_ASPNETCORE_DISABLE_START_UP_ERROR_PAGE); - // This will not include environment variables defined in the web.config. - // Reading environment variables can be added here, but it adds more code to the shim. - const auto detailedErrors = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_DETAILEDERRORS").value_or(L""); - const auto aspnetCoreEnvironment = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_ENVIRONMENT").value_or(L""); - const auto dotnetEnvironment = Environment::GetEnvironmentVariableValue(L"DOTNET_ENVIRONMENT").value_or(L""); + auto environmentVariables = section->GetMap(CS_ASPNETCORE_ENVIRONMENT_VARIABLES); + + // Indexing into environment variable map will add a default entry if none is present + // This is okay here as we throw away the map shortly after. + // Process set environment variables are prioritized over web config variables. + const auto detailedErrors = Environment::GetEnvironmentVariableValue(CS_ASPNETCORE_DETAILEDERRORS) + .value_or(environmentVariables[CS_ASPNETCORE_DETAILEDERRORS]); + const auto aspnetCoreEnvironment = Environment::GetEnvironmentVariableValue(CS_ASPNETCORE_ENVIRONMENT) + .value_or(environmentVariables[CS_ASPNETCORE_ENVIRONMENT]); + const auto dotnetEnvironment = Environment::GetEnvironmentVariableValue(CS_DOTNET_ENVIRONMENT) + .value_or(environmentVariables[CS_DOTNET_ENVIRONMENT]); auto detailedErrorsEnabled = equals_ignore_case(L"1", detailedErrors) || equals_ignore_case(L"true", detailedErrors); auto aspnetCoreEnvironmentEnabled = equals_ignore_case(L"Development", aspnetCoreEnvironment); diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h index 446f8c7d4b..ae02dd3faa 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/ConfigurationSection.h @@ -30,6 +30,9 @@ #define CS_ENABLED L"enabled" #define CS_ASPNETCORE_HANDLER_CALL_STARTUP_HOOK L"callStartupHook" #define CS_ASPNETCORE_HANDLER_STACK_SIZE L"stackSize" +#define CS_ASPNETCORE_DETAILEDERRORS L"ASPNETCORE_DETAILEDERRORS" +#define CS_ASPNETCORE_ENVIRONMENT L"ASPNETCORE_ENVIRONMENT" +#define CS_DOTNET_ENVIRONMENT L"DOTNET_ENVIRONMENT" class ConfigurationSection: NonCopyable { diff --git a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp index 118a67198b..fb63cdb20c 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/CommonLib/Environment.cpp @@ -47,10 +47,10 @@ Environment::GetEnvironmentVariableValue(const std::wstring & str) } else if (requestedSize == 1) { - // String just contains a nullcharacter, return empty string + // String just contains a nullcharacter, return nothing // GetEnvironmentVariableW has inconsistent behavior when returning size for an empty // environment variable. - return L""; + return std::nullopt; } std::wstring expandedStr; diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs index d6ffd044c9..686164f3cf 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/StartupTests.cs @@ -365,6 +365,26 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess EventLogHelpers.VerifyEventLogEvent(deploymentResult, EventLogHelpers.InProcessFailedToFindNativeDependencies(deploymentResult), Logger); } + [ConditionalFact] + public async Task TargedDifferenceSharedFramework_FailedToFindNativeDependenciesErrorInResponse() + { + var deploymentParameters = Fixture.GetBaseDeploymentParameters(Fixture.InProcessTestSite); + deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_DETAILEDERRORS"] = "TRUE"; + var deploymentResult = await DeployAsync(deploymentParameters); + + Helpers.ModifyFrameworkVersionInRuntimeConfig(deploymentResult); + if (DeployerSelector.HasNewShim) + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult, "HTTP Error 500.31 - ANCM Failed to Find Native Dependencies"); + var responseString = await deploymentResult.HttpClient.GetStringAsync("/HelloWorld"); + Assert.Contains("The specified framework 'Microsoft.NETCore.App', version '2.9.9'", responseString); + } + else + { + await AssertSiteFailsToStartWithInProcessStaticContent(deploymentResult); + } + } + [ConditionalFact] public async Task RemoveInProcessReference_FailedToFindRequestHandler() { @@ -662,7 +682,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess deploymentParameters.TransformArguments((a, _) => $"{a} Throw"); // Deployment parameters by default set ASPNETCORE_DETAILEDERRORS to true - deploymentParameters.EnvironmentVariables["ASPNETCORE_DETAILEDERRORS"] = ""; + deploymentParameters.EnvironmentVariables.Remove("ASPNETCORE_DETAILEDERRORS"); deploymentParameters.EnvironmentVariables[environmentVariable] = value; var deploymentResult = await DeployAsync(deploymentParameters); @@ -678,6 +698,30 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess VerifyDotnetRuntimeEventLog(deploymentResult); } + [ConditionalFact] + [RequiresNewHandler] + public async Task ExceptionIsLoggedToEventLogAndPutInResponseWhenDeveloperExceptionPageIsEnabledViaWebConfig() + { + var deploymentParameters = Fixture.GetBaseDeploymentParameters(); + deploymentParameters.TransformArguments((a, _) => $"{a} Throw"); + + // Deployment parameters by default set ASPNETCORE_DETAILEDERRORS to true + deploymentParameters.EnvironmentVariables.Remove("ASPNETCORE_DETAILEDERRORS"); + deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_DETAILEDERRORS"] = "TRUE"; + + var deploymentResult = await DeployAsync(deploymentParameters); + var result = await deploymentResult.HttpClient.GetAsync("/"); + Assert.False(result.IsSuccessStatusCode); + + var content = await result.Content.ReadAsStringAsync(); + Assert.Contains("InvalidOperationException", content); + Assert.Contains("TestSite.Program.Main", content); + + StopServer(); + + VerifyDotnetRuntimeEventLog(deploymentResult); + } + [ConditionalTheory] [RequiresIIS(IISCapability.PoolEnvironmentVariables)] [RequiresNewHandler]