From 56435e76948211ebb2db167776f6f246b8bc464b Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Mon, 5 Dec 2022 10:55:51 -0800 Subject: [PATCH 1/6] Do not override content root with default --- .../src/HostApplicationBuilder.cs | 7 ++++++- .../src/HostingHostBuilderExtensions.cs | 11 ++++++++++- .../UnitTests/HostApplicationBuilderTests.cs | 18 +++++++++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/HostApplicationBuilder.cs b/src/libraries/Microsoft.Extensions.Hosting/src/HostApplicationBuilder.cs index c26fdad6b74734..9962638c49d6aa 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/HostApplicationBuilder.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/src/HostApplicationBuilder.cs @@ -88,7 +88,12 @@ public HostApplicationBuilder(HostApplicationBuilderSettings? settings) if (!settings.DisableDefaults) { - HostingHostBuilderExtensions.ApplyDefaultHostConfiguration(Configuration, settings.Args); + if (settings.ContentRootPath is null && Configuration[HostDefaults.ContentRootKey] is null) + { + HostingHostBuilderExtensions.SetDefaultContentRoot(Configuration); + } + + HostingHostBuilderExtensions.AddDefaultHostConfigurationSources(Configuration, settings.Args); } // HostApplicationBuilderSettings override all other config sources. diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs b/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs index b8e8c207f650a3..c3e8c1941b4b41 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs @@ -198,7 +198,7 @@ public static IHostBuilder ConfigureDefaults(this IHostBuilder builder, string[] .UseServiceProviderFactory(context => new DefaultServiceProviderFactory(CreateDefaultServiceProviderOptions(context))); } - internal static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostConfigBuilder, string[]? args) + internal static void SetDefaultContentRoot(IConfigurationBuilder hostConfigBuilder) { // If we're running anywhere other than C:\Windows\system32, we default to using the CWD for the ContentRoot. // However, since many things like Windows services and MSIX installers have C:\Windows\system32 as there CWD which is not likely @@ -216,7 +216,10 @@ internal static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostCon new KeyValuePair(HostDefaults.ContentRootKey, cwd), }); } + } + internal static void AddDefaultHostConfigurationSources(IConfigurationBuilder hostConfigBuilder, string[]? args) + { hostConfigBuilder.AddEnvironmentVariables(prefix: "DOTNET_"); if (args is { Length: > 0 }) { @@ -224,6 +227,12 @@ internal static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostCon } } + private static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostConfigBuilder, string[]? args) + { + SetDefaultContentRoot(hostConfigBuilder); + AddDefaultHostConfigurationSources(hostConfigBuilder, args); + } + internal static void ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args) { IHostEnvironment env = hostingContext.HostingEnvironment; diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs index 458bf37eb7d005..5bbaa68e2cc977 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs @@ -229,34 +229,46 @@ public void DisableDefaultIHostEnvironmentValues() Assert.IsAssignableFrom(env.ContentRootFileProvider); } - [Fact] - public void ConfigurationSettingCanInfluenceEnvironment() + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ConfigurationSettingCanInfluenceEnvironment(bool disableDefaults) { + var tempPath = Path.GetTempPath(); + using var config = new ConfigurationManager(); config.AddInMemoryCollection(new KeyValuePair[] { new(HostDefaults.ApplicationKey, "AppA" ), new(HostDefaults.EnvironmentKey, "EnvA" ), + new(HostDefaults.ContentRootKey, tempPath) }); var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings { - DisableDefaults = true, + DisableDefaults = disableDefaults, Configuration = config, }); Assert.Equal("AppA", builder.Configuration[HostDefaults.ApplicationKey]); Assert.Equal("EnvA", builder.Configuration[HostDefaults.EnvironmentKey]); + Assert.Equal(tempPath, builder.Configuration[HostDefaults.ContentRootKey]); Assert.Equal("AppA", builder.Environment.ApplicationName); Assert.Equal("EnvA", builder.Environment.EnvironmentName); + Assert.Equal(tempPath, builder.Environment.ContentRootPath); + var fileProviderFromBuilder = Assert.IsType(builder.Environment.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromBuilder.Root); using IHost host = builder.Build(); var hostEnvironmentFromServices = host.Services.GetRequiredService(); Assert.Equal("AppA", hostEnvironmentFromServices.ApplicationName); Assert.Equal("EnvA", hostEnvironmentFromServices.EnvironmentName); + Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath); + var fileProviderFromServices = Assert.IsType(hostEnvironmentFromServices.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromServices.Root); } [Fact] From 8a2fc7699a53d9a833bfa28083543d323fbb37d6 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 6 Dec 2022 17:45:11 -0800 Subject: [PATCH 2/6] Address PR feedback --- .../src/HostingHostBuilderExtensions.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs b/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs index c3e8c1941b4b41..5663e5fbb3c466 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/src/HostingHostBuilderExtensions.cs @@ -198,6 +198,12 @@ public static IHostBuilder ConfigureDefaults(this IHostBuilder builder, string[] .UseServiceProviderFactory(context => new DefaultServiceProviderFactory(CreateDefaultServiceProviderOptions(context))); } + private static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostConfigBuilder, string[]? args) + { + SetDefaultContentRoot(hostConfigBuilder); + AddDefaultHostConfigurationSources(hostConfigBuilder, args); + } + internal static void SetDefaultContentRoot(IConfigurationBuilder hostConfigBuilder) { // If we're running anywhere other than C:\Windows\system32, we default to using the CWD for the ContentRoot. @@ -227,12 +233,6 @@ internal static void AddDefaultHostConfigurationSources(IConfigurationBuilder ho } } - private static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostConfigBuilder, string[]? args) - { - SetDefaultContentRoot(hostConfigBuilder); - AddDefaultHostConfigurationSources(hostConfigBuilder, args); - } - internal static void ApplyDefaultAppConfiguration(HostBuilderContext hostingContext, IConfigurationBuilder appConfigBuilder, string[]? args) { IHostEnvironment env = hostingContext.HostingEnvironment; From 68b8e1da577914d4d7b048d8257f2eb600ae07c6 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 6 Dec 2022 17:46:47 -0800 Subject: [PATCH 3/6] Add more test coverage for custom HostApplicationBuilderSettings --- .../UnitTests/HostApplicationBuilderTests.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs index 5bbaa68e2cc977..d363814623f5d5 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs @@ -271,9 +271,13 @@ public void ConfigurationSettingCanInfluenceEnvironment(bool disableDefaults) Assert.Equal(tempPath, fileProviderFromServices.Root); } - [Fact] - public void DirectSettingsOverrideConfigurationSetting() + [Theory] + [InlineData(true)] + [InlineData(false)] + public void DirectSettingsOverrideConfigurationSetting(bool disableDefaults) { + var tempPath = Path.GetTempPath(); + using var config = new ConfigurationManager(); config.AddInMemoryCollection(new KeyValuePair[] @@ -284,23 +288,31 @@ public void DirectSettingsOverrideConfigurationSetting() var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings { - DisableDefaults = true, + DisableDefaults = disableDefaults, Configuration = config, ApplicationName = "AppB", EnvironmentName = "EnvB", + ContentRootPath = tempPath, }); Assert.Equal("AppB", builder.Configuration[HostDefaults.ApplicationKey]); Assert.Equal("EnvB", builder.Configuration[HostDefaults.EnvironmentKey]); + Assert.Equal(tempPath, builder.Configuration[HostDefaults.ContentRootKey]); Assert.Equal("AppB", builder.Environment.ApplicationName); Assert.Equal("EnvB", builder.Environment.EnvironmentName); + Assert.Equal(tempPath, builder.Environment.ContentRootPath); + var fileProviderFromBuilder = Assert.IsType(builder.Environment.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromBuilder.Root); using IHost host = builder.Build(); var hostEnvironmentFromServices = host.Services.GetRequiredService(); Assert.Equal("AppB", hostEnvironmentFromServices.ApplicationName); Assert.Equal("EnvB", hostEnvironmentFromServices.EnvironmentName); + Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath); + var fileProviderFromServices = Assert.IsType(hostEnvironmentFromServices.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromServices.Root); } [Fact] From b0886bb9032dc192490aeeac290541bfa0f1b9b8 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Thu, 8 Dec 2022 13:25:47 -0800 Subject: [PATCH 4/6] Make package authoring changes --- .../src/Microsoft.Extensions.Hosting.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj b/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj index 945760c9aa144c..5d749293051467 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj @@ -6,6 +6,8 @@ Hosting and startup infrastructures for applications. true true + true + 1 From 801d39fb11a43f045196ff514d736ce45859feff Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 3 Jan 2023 13:20:19 -0600 Subject: [PATCH 5/6] Fix failing Hosting tests (#79455) Ensure the temp directory used is always empty, so it doesn't pick up appsettings.json files randomly. Fix #79453 --- .../UnitTests/HostApplicationBuilderTests.cs | 154 +++++++++++------- 1 file changed, 96 insertions(+), 58 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs index d363814623f5d5..d5ba003153769e 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/HostApplicationBuilderTests.cs @@ -234,41 +234,48 @@ public void DisableDefaultIHostEnvironmentValues() [InlineData(false)] public void ConfigurationSettingCanInfluenceEnvironment(bool disableDefaults) { - var tempPath = Path.GetTempPath(); + var tempPath = CreateTempSubdirectory(); - using var config = new ConfigurationManager(); - - config.AddInMemoryCollection(new KeyValuePair[] + try { - new(HostDefaults.ApplicationKey, "AppA" ), - new(HostDefaults.EnvironmentKey, "EnvA" ), - new(HostDefaults.ContentRootKey, tempPath) - }); + using var config = new ConfigurationManager(); - var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings - { - DisableDefaults = disableDefaults, - Configuration = config, - }); + config.AddInMemoryCollection(new KeyValuePair[] + { + new(HostDefaults.ApplicationKey, "AppA" ), + new(HostDefaults.EnvironmentKey, "EnvA" ), + new(HostDefaults.ContentRootKey, tempPath) + }); - Assert.Equal("AppA", builder.Configuration[HostDefaults.ApplicationKey]); - Assert.Equal("EnvA", builder.Configuration[HostDefaults.EnvironmentKey]); - Assert.Equal(tempPath, builder.Configuration[HostDefaults.ContentRootKey]); + var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings + { + DisableDefaults = disableDefaults, + Configuration = config, + }); - Assert.Equal("AppA", builder.Environment.ApplicationName); - Assert.Equal("EnvA", builder.Environment.EnvironmentName); - Assert.Equal(tempPath, builder.Environment.ContentRootPath); - var fileProviderFromBuilder = Assert.IsType(builder.Environment.ContentRootFileProvider); - Assert.Equal(tempPath, fileProviderFromBuilder.Root); + Assert.Equal("AppA", builder.Configuration[HostDefaults.ApplicationKey]); + Assert.Equal("EnvA", builder.Configuration[HostDefaults.EnvironmentKey]); + Assert.Equal(tempPath, builder.Configuration[HostDefaults.ContentRootKey]); - using IHost host = builder.Build(); + Assert.Equal("AppA", builder.Environment.ApplicationName); + Assert.Equal("EnvA", builder.Environment.EnvironmentName); + Assert.Equal(tempPath, builder.Environment.ContentRootPath); + var fileProviderFromBuilder = Assert.IsType(builder.Environment.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromBuilder.Root); - var hostEnvironmentFromServices = host.Services.GetRequiredService(); - Assert.Equal("AppA", hostEnvironmentFromServices.ApplicationName); - Assert.Equal("EnvA", hostEnvironmentFromServices.EnvironmentName); - Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath); - var fileProviderFromServices = Assert.IsType(hostEnvironmentFromServices.ContentRootFileProvider); - Assert.Equal(tempPath, fileProviderFromServices.Root); + using IHost host = builder.Build(); + + var hostEnvironmentFromServices = host.Services.GetRequiredService(); + Assert.Equal("AppA", hostEnvironmentFromServices.ApplicationName); + Assert.Equal("EnvA", hostEnvironmentFromServices.EnvironmentName); + Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath); + var fileProviderFromServices = Assert.IsType(hostEnvironmentFromServices.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromServices.Root); + } + finally + { + Directory.Delete(tempPath); + } } [Theory] @@ -276,43 +283,74 @@ public void ConfigurationSettingCanInfluenceEnvironment(bool disableDefaults) [InlineData(false)] public void DirectSettingsOverrideConfigurationSetting(bool disableDefaults) { - var tempPath = Path.GetTempPath(); - - using var config = new ConfigurationManager(); + var tempPath = CreateTempSubdirectory(); - config.AddInMemoryCollection(new KeyValuePair[] + try { - new(HostDefaults.ApplicationKey, "AppA" ), - new(HostDefaults.EnvironmentKey, "EnvA" ), - }); + using var config = new ConfigurationManager(); - var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings - { - DisableDefaults = disableDefaults, - Configuration = config, - ApplicationName = "AppB", - EnvironmentName = "EnvB", - ContentRootPath = tempPath, - }); + config.AddInMemoryCollection(new KeyValuePair[] + { + new(HostDefaults.ApplicationKey, "AppA" ), + new(HostDefaults.EnvironmentKey, "EnvA" ), + }); - Assert.Equal("AppB", builder.Configuration[HostDefaults.ApplicationKey]); - Assert.Equal("EnvB", builder.Configuration[HostDefaults.EnvironmentKey]); - Assert.Equal(tempPath, builder.Configuration[HostDefaults.ContentRootKey]); + var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings + { + DisableDefaults = disableDefaults, + Configuration = config, + ApplicationName = "AppB", + EnvironmentName = "EnvB", + ContentRootPath = tempPath, + }); - Assert.Equal("AppB", builder.Environment.ApplicationName); - Assert.Equal("EnvB", builder.Environment.EnvironmentName); - Assert.Equal(tempPath, builder.Environment.ContentRootPath); - var fileProviderFromBuilder = Assert.IsType(builder.Environment.ContentRootFileProvider); - Assert.Equal(tempPath, fileProviderFromBuilder.Root); + Assert.Equal("AppB", builder.Configuration[HostDefaults.ApplicationKey]); + Assert.Equal("EnvB", builder.Configuration[HostDefaults.EnvironmentKey]); + Assert.Equal(tempPath, builder.Configuration[HostDefaults.ContentRootKey]); - using IHost host = builder.Build(); + Assert.Equal("AppB", builder.Environment.ApplicationName); + Assert.Equal("EnvB", builder.Environment.EnvironmentName); + Assert.Equal(tempPath, builder.Environment.ContentRootPath); + var fileProviderFromBuilder = Assert.IsType(builder.Environment.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromBuilder.Root); - var hostEnvironmentFromServices = host.Services.GetRequiredService(); - Assert.Equal("AppB", hostEnvironmentFromServices.ApplicationName); - Assert.Equal("EnvB", hostEnvironmentFromServices.EnvironmentName); - Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath); - var fileProviderFromServices = Assert.IsType(hostEnvironmentFromServices.ContentRootFileProvider); - Assert.Equal(tempPath, fileProviderFromServices.Root); + using IHost host = builder.Build(); + + var hostEnvironmentFromServices = host.Services.GetRequiredService(); + Assert.Equal("AppB", hostEnvironmentFromServices.ApplicationName); + Assert.Equal("EnvB", hostEnvironmentFromServices.EnvironmentName); + Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath); + var fileProviderFromServices = Assert.IsType(hostEnvironmentFromServices.ContentRootFileProvider); + Assert.Equal(tempPath, fileProviderFromServices.Root); + } + finally + { + Directory.Delete(tempPath); + } + } + + private static string CreateTempSubdirectory() + { +#if NETCOREAPP + DirectoryInfo directoryInfo = Directory.CreateTempSubdirectory(); +#else + DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName())); + directoryInfo.Create(); +#endif + + // PhysicalFileProvider will always ensure the path has a trailing slash + return EnsureTrailingSlash(directoryInfo.FullName); + } + + private static string EnsureTrailingSlash(string path) + { + if (!string.IsNullOrEmpty(path) && + path[path.Length - 1] != Path.DirectorySeparatorChar) + { + return path + Path.DirectorySeparatorChar; + } + + return path; } [Fact] From 0d9f9bb4c28653eb8f9fcbe7de512cf4bb0d2025 Mon Sep 17 00:00:00 2001 From: Eric StJohn Date: Wed, 11 Jan 2023 13:49:02 -0800 Subject: [PATCH 6/6] Add reference to System.Diagnostics.DiagnosticSource --- .../src/Microsoft.Extensions.Hosting.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj b/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj index 81b1279805ffd1..d939261f252b56 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj +++ b/src/libraries/Microsoft.Extensions.Hosting/src/Microsoft.Extensions.Hosting.csproj @@ -53,6 +53,7 @@ +