Skip to content

Commit

Permalink
[release/7.0] Do not override content root with default (#79411)
Browse files Browse the repository at this point in the history
* Do not override content root with default

* Address PR feedback

* Add more test coverage for custom HostApplicationBuilderSettings

* Make package authoring changes

* 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

* Add reference to System.Diagnostics.DiagnosticSource

Co-authored-by: Stephen Halter <halter73@gmail.com>
Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
Co-authored-by: Eric StJohn <ericstj@microsoft.com>
  • Loading branch information
4 people authored Jan 12, 2023
1 parent 600c612 commit b1a37a3
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,13 @@ public static IHostBuilder ConfigureDefaults(this IHostBuilder builder, string[]
.UseServiceProviderFactory(context => new DefaultServiceProviderFactory(CreateDefaultServiceProviderOptions(context)));
}

internal static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostConfigBuilder, string[]? args)
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.
// However, since many things like Windows services and MSIX installers have C:\Windows\system32 as there CWD which is not likely
Expand All @@ -216,7 +222,10 @@ internal static void ApplyDefaultHostConfiguration(IConfigurationBuilder hostCon
new KeyValuePair<string, string?>(HostDefaults.ContentRootKey, cwd),
});
}
}

internal static void AddDefaultHostConfigurationSources(IConfigurationBuilder hostConfigBuilder, string[]? args)
{
hostConfigBuilder.AddEnvironmentVariables(prefix: "DOTNET_");
if (args is { Length: > 0 })
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<EnableAOTAnalyzer>true</EnableAOTAnalyzer>
<IsPackable>true</IsPackable>
<PackageDescription>Hosting and startup infrastructures for applications.</PackageDescription>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<ServicingVersion>1</ServicingVersion>
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -51,6 +53,7 @@
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Logging.EventLog\src\Microsoft.Extensions.Logging.EventLog.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Logging.EventSource\src\Microsoft.Extensions.Logging.EventSource.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)Microsoft.Extensions.Options\src\Microsoft.Extensions.Options.csproj" />
<ProjectReference Include="$(LibrariesProjectRoot)System.Diagnostics.DiagnosticSource\src\System.Diagnostics.DiagnosticSource.csproj" />
</ItemGroup>

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'netstandard2.1'))">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,66 +229,128 @@ public void DisableDefaultIHostEnvironmentValues()
Assert.IsAssignableFrom<PhysicalFileProvider>(env.ContentRootFileProvider);
}

[Fact]
public void ConfigurationSettingCanInfluenceEnvironment()
[Theory]
[InlineData(true)]
[InlineData(false)]
public void ConfigurationSettingCanInfluenceEnvironment(bool disableDefaults)
{
using var config = new ConfigurationManager();
var tempPath = CreateTempSubdirectory();

config.AddInMemoryCollection(new KeyValuePair<string, string>[]
try
{
new(HostDefaults.ApplicationKey, "AppA" ),
new(HostDefaults.EnvironmentKey, "EnvA" ),
});
using var config = new ConfigurationManager();

var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings
{
DisableDefaults = true,
Configuration = config,
});
config.AddInMemoryCollection(new KeyValuePair<string, string>[]
{
new(HostDefaults.ApplicationKey, "AppA" ),
new(HostDefaults.EnvironmentKey, "EnvA" ),
new(HostDefaults.ContentRootKey, tempPath)
});

var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings
{
DisableDefaults = disableDefaults,
Configuration = config,
});

Assert.Equal("AppA", builder.Configuration[HostDefaults.ApplicationKey]);
Assert.Equal("EnvA", builder.Configuration[HostDefaults.EnvironmentKey]);
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("AppA", builder.Environment.ApplicationName);
Assert.Equal("EnvA", builder.Environment.EnvironmentName);
Assert.Equal(tempPath, builder.Environment.ContentRootPath);
var fileProviderFromBuilder = Assert.IsType<PhysicalFileProvider>(builder.Environment.ContentRootFileProvider);
Assert.Equal(tempPath, fileProviderFromBuilder.Root);

using IHost host = builder.Build();
using IHost host = builder.Build();

var hostEnvironmentFromServices = host.Services.GetRequiredService<IHostEnvironment>();
Assert.Equal("AppA", hostEnvironmentFromServices.ApplicationName);
Assert.Equal("EnvA", hostEnvironmentFromServices.EnvironmentName);
var hostEnvironmentFromServices = host.Services.GetRequiredService<IHostEnvironment>();
Assert.Equal("AppA", hostEnvironmentFromServices.ApplicationName);
Assert.Equal("EnvA", hostEnvironmentFromServices.EnvironmentName);
Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath);
var fileProviderFromServices = Assert.IsType<PhysicalFileProvider>(hostEnvironmentFromServices.ContentRootFileProvider);
Assert.Equal(tempPath, fileProviderFromServices.Root);
}
finally
{
Directory.Delete(tempPath);
}
}

[Fact]
public void DirectSettingsOverrideConfigurationSetting()
[Theory]
[InlineData(true)]
[InlineData(false)]
public void DirectSettingsOverrideConfigurationSetting(bool disableDefaults)
{
using var config = new ConfigurationManager();
var tempPath = CreateTempSubdirectory();

config.AddInMemoryCollection(new KeyValuePair<string, string>[]
try
{
new(HostDefaults.ApplicationKey, "AppA" ),
new(HostDefaults.EnvironmentKey, "EnvA" ),
});
using var config = new ConfigurationManager();

var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings
{
DisableDefaults = true,
Configuration = config,
ApplicationName = "AppB",
EnvironmentName = "EnvB",
});
config.AddInMemoryCollection(new KeyValuePair<string, string>[]
{
new(HostDefaults.ApplicationKey, "AppA" ),
new(HostDefaults.EnvironmentKey, "EnvA" ),
});

Assert.Equal("AppB", builder.Configuration[HostDefaults.ApplicationKey]);
Assert.Equal("EnvB", builder.Configuration[HostDefaults.EnvironmentKey]);
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("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<PhysicalFileProvider>(builder.Environment.ContentRootFileProvider);
Assert.Equal(tempPath, fileProviderFromBuilder.Root);

var hostEnvironmentFromServices = host.Services.GetRequiredService<IHostEnvironment>();
Assert.Equal("AppB", hostEnvironmentFromServices.ApplicationName);
Assert.Equal("EnvB", hostEnvironmentFromServices.EnvironmentName);
using IHost host = builder.Build();

var hostEnvironmentFromServices = host.Services.GetRequiredService<IHostEnvironment>();
Assert.Equal("AppB", hostEnvironmentFromServices.ApplicationName);
Assert.Equal("EnvB", hostEnvironmentFromServices.EnvironmentName);
Assert.Equal(tempPath, hostEnvironmentFromServices.ContentRootPath);
var fileProviderFromServices = Assert.IsType<PhysicalFileProvider>(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]
Expand Down

0 comments on commit b1a37a3

Please sign in to comment.