Skip to content
代码片段 群组 项目
未验证 提交 366a6180 编辑于 作者: David Fowler's avatar David Fowler 提交者: GitHub
浏览文件

Normalize the content root and improve errors (#36990)

* Normalize the content root and improve errors
- When trying to compare content root paths, make sure the paths are normalized before doing so. Today we throw too aggresively when libraries try to set the content root, even if that would have resulted in a noop. This change normalizes the initial path and the attempted path before doing the comparison.
- We also improve the error message when the user tries to change the host settings, directing them to the correct API to use instead.

* PR feedbacj

* Make it static

* Resolve the full path to handle . and ..

* Linux paths
上级 5a50336d
No related branches found
No related tags found
无相关合并请求
......@@ -107,11 +107,14 @@ namespace Microsoft.AspNetCore.Hosting
{
ApplicationName = hostConfiguration[HostDefaults.ApplicationKey],
EnvironmentName = hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production,
ContentRootPath = HostingEnvironment.ResolveContentRootPath(hostConfiguration[HostDefaults.ContentRootKey], AppContext.BaseDirectory),
ContentRootPath = ContentRootResolver.ResolvePath(hostConfiguration[HostDefaults.ContentRootKey]),
};
hostingEnvironment.ContentRootFileProvider = new PhysicalFileProvider(hostingEnvironment.ContentRootPath);
// Normalize the content root setting for the path in configuration
hostConfiguration[HostDefaults.ContentRootKey] = hostingEnvironment.ContentRootPath;
var hostContext = new HostBuilderContext(Properties)
{
Configuration = hostConfiguration,
......@@ -155,19 +158,6 @@ namespace Microsoft.AspNetCore.Hosting
public string ApplicationName { get; set; } = default!;
public string ContentRootPath { get; set; } = default!;
public IFileProvider ContentRootFileProvider { get; set; } = default!;
public static string ResolveContentRootPath(string contentRootPath, string basePath)
{
if (string.IsNullOrEmpty(contentRootPath))
{
return basePath;
}
if (Path.IsPathRooted(contentRootPath))
{
return contentRootPath;
}
return Path.Combine(Path.GetFullPath(basePath), contentRootPath);
}
}
}
}
......@@ -60,7 +60,8 @@ namespace Microsoft.AspNetCore.Builder
public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
{
var previousApplicationName = _configuration[HostDefaults.ApplicationKey];
var previousContentRoot = _configuration[HostDefaults.ContentRootKey];
// Use the real content root so we can compare paths
var previousContentRoot = _context.HostingEnvironment.ContentRootPath;
var previousEnvironment = _configuration[HostDefaults.EnvironmentKey];
// Run these immediately so that they are observable by the imperative code
......@@ -70,17 +71,17 @@ namespace Microsoft.AspNetCore.Builder
// and done other things based on environment name, application name or content root.
if (!string.Equals(previousApplicationName, _configuration[HostDefaults.ApplicationKey], StringComparison.OrdinalIgnoreCase))
{
throw new NotSupportedException("The application name changed. Changing the host configuration is not supported");
throw new NotSupportedException($"The application name changed from \"{previousApplicationName}\" to \"{_configuration[HostDefaults.ApplicationKey]}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
if (!string.Equals(previousContentRoot, _configuration[HostDefaults.ContentRootKey], StringComparison.OrdinalIgnoreCase))
if (!string.Equals(previousContentRoot, ContentRootResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey]), StringComparison.OrdinalIgnoreCase))
{
throw new NotSupportedException("The content root changed. Changing the host configuration is not supported");
throw new NotSupportedException($"The content root changed from \"{previousContentRoot}\" to \"{ContentRootResolver.ResolvePath(_configuration[HostDefaults.ContentRootKey])}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
if (!string.Equals(previousEnvironment, _configuration[HostDefaults.EnvironmentKey], StringComparison.OrdinalIgnoreCase))
{
throw new NotSupportedException("The environment changed. Changing the host configuration is not supported");
throw new NotSupportedException($"The environment changed from \"{previousEnvironment}\" to \"{_configuration[HostDefaults.EnvironmentKey]}\". Changing the host configuration using WebApplicationBuilder.Host is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
return this;
......
......@@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Builder
/// <inheritdoc />
public IWebHostBuilder ConfigureAppConfiguration(Action<WebHostBuilderContext, IConfigurationBuilder> configureDelegate)
{
var previousContentRoot = _configuration[WebHostDefaults.ContentRootKey];
var previousContentRoot = _context.HostingEnvironment.ContentRootPath;
var previousWebRoot = _configuration[WebHostDefaults.ContentRootKey];
var previousApplication = _configuration[WebHostDefaults.ApplicationKey];
var previousEnvironment = _configuration[WebHostDefaults.EnvironmentKey];
......@@ -57,27 +57,27 @@ namespace Microsoft.AspNetCore.Builder
else if (!string.Equals(previousApplication, _configuration[WebHostDefaults.ApplicationKey], StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The application name changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The application name changed from \"{previousApplication}\" to \"{_configuration[WebHostDefaults.ApplicationKey]}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (!string.Equals(previousContentRoot, _configuration[WebHostDefaults.ContentRootKey], StringComparison.OrdinalIgnoreCase))
else if (!string.Equals(previousContentRoot, ContentRootResolver.ResolvePath(_configuration[WebHostDefaults.ContentRootKey]), StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The content root changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The content root changed from \"{previousContentRoot}\" to \"{ContentRootResolver.ResolvePath(_configuration[WebHostDefaults.ContentRootKey])}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (!string.Equals(previousEnvironment, _configuration[WebHostDefaults.EnvironmentKey], StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The environment changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The environment changed from \"{previousEnvironment}\" to \"{_configuration[WebHostDefaults.EnvironmentKey]}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (!string.Equals(previousHostingStartupAssemblies, _configuration[WebHostDefaults.HostingStartupAssembliesKey], StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The hosting startup assemblies changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The hosting startup assemblies changed from \"{previousHostingStartupAssemblies}\" to \"{_configuration[WebHostDefaults.HostingStartupAssembliesKey]}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (!string.Equals(previousHostingStartupAssembliesExclude, _configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey], StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The hosting startup assemblies exclude list changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The hosting startup assemblies exclude list changed from \"{previousHostingStartupAssembliesExclude}\" to \"{_configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey]}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
return this;
......@@ -112,36 +112,47 @@ namespace Microsoft.AspNetCore.Builder
return this;
}
var previousContentRoot = _context.HostingEnvironment.ContentRootPath;
var previousApplication = _configuration[WebHostDefaults.ApplicationKey];
var previousEnvironment = _configuration[WebHostDefaults.EnvironmentKey];
var previousHostingStartupAssemblies = _configuration[WebHostDefaults.HostingStartupAssembliesKey];
var previousHostingStartupAssembliesExclude = _configuration[WebHostDefaults.HostingStartupExcludeAssembliesKey];
if (string.Equals(key, WebHostDefaults.WebRootKey, StringComparison.OrdinalIgnoreCase))
{
// We allow changing the web root since it's based off the content root and typically
// read after the host is built.
_environment.WebRootPath = Path.Combine(_environment.ContentRootPath, value);
}
else if (string.Equals(key, WebHostDefaults.ApplicationKey, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(key, WebHostDefaults.ApplicationKey, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(previousApplication, value, StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The application name changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The application name changed from \"{previousApplication}\" to \"{value}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (string.Equals(key, WebHostDefaults.ContentRootKey, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(key, WebHostDefaults.ContentRootKey, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(previousContentRoot, ContentRootResolver.ResolvePath(value), StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The content root changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The content root changed from \"{previousContentRoot}\" to \"{ContentRootResolver.ResolvePath(value)}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (string.Equals(key, WebHostDefaults.EnvironmentKey, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(key, WebHostDefaults.EnvironmentKey, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(previousEnvironment, value, StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The environment changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The environment changed from \"{previousEnvironment}\" to \"{value}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (string.Equals(key, WebHostDefaults.HostingStartupAssembliesKey, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(key, WebHostDefaults.HostingStartupAssembliesKey, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(previousHostingStartupAssemblies, value, StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The hosting startup assemblies changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The hosting startup assemblies changed from \"{previousHostingStartupAssemblies}\" to \"{value}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
else if (string.Equals(key, WebHostDefaults.HostingStartupExcludeAssembliesKey, StringComparison.OrdinalIgnoreCase))
else if (string.Equals(key, WebHostDefaults.HostingStartupExcludeAssembliesKey, StringComparison.OrdinalIgnoreCase) &&
!string.Equals(previousHostingStartupAssembliesExclude, value, StringComparison.OrdinalIgnoreCase))
{
// Disallow changing any host configuration
throw new NotSupportedException("The hosting startup assemblies exclude list changed. Changing the host configuration is not supported.");
throw new NotSupportedException($"The hosting startup assemblies exclude list changed from \"{previousHostingStartupAssembliesExclude}\" to \"{value}\". Changing the host configuration using WebApplicationBuilder.WebHost is not supported. Use WebApplication.CreateBuilder(WebApplicationOptions) instead.");
}
// Set the configuration value after we've validated the key
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Microsoft.AspNetCore
{
internal static class ContentRootResolver
{
public static string ResolvePath(string contentRootPath)
{
var canonicalPath = ResolvePath(contentRootPath, AppContext.BaseDirectory);
return Path.EndsInDirectorySeparator(canonicalPath) ? canonicalPath : canonicalPath + Path.DirectorySeparatorChar;
}
private static string ResolvePath(string contentRootPath, string basePath)
{
if (string.IsNullOrEmpty(contentRootPath))
{
return Path.GetFullPath(basePath);
}
if (Path.IsPathRooted(contentRootPath))
{
return Path.GetFullPath(contentRootPath);
}
return Path.GetFullPath(Path.Combine(Path.GetFullPath(basePath), contentRootPath));
}
}
}
......@@ -300,6 +300,54 @@ namespace Microsoft.AspNetCore.Tests
}));
}
[Fact]
public void SettingContentRootToSameCanonicalValueWorks()
{
var contentRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(contentRoot);
try
{
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
ContentRootPath = contentRoot
});
builder.Host.UseContentRoot(contentRoot + Path.DirectorySeparatorChar);
builder.Host.UseContentRoot(contentRoot.ToUpperInvariant());
builder.Host.UseContentRoot(contentRoot.ToLowerInvariant());
builder.WebHost.UseContentRoot(contentRoot + Path.DirectorySeparatorChar);
builder.WebHost.UseContentRoot(contentRoot.ToUpperInvariant());
builder.WebHost.UseContentRoot(contentRoot.ToLowerInvariant());
}
finally
{
Directory.Delete(contentRoot);
}
}
[Theory]
[InlineData("")] // Empty behaves differently to null
[InlineData(".")]
public void SettingContentRootToRelativePathUsesAppContextBaseDirectoryAsPathBase(string path)
{
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
ContentRootPath = path
});
builder.Host.UseContentRoot(AppContext.BaseDirectory);
builder.Host.UseContentRoot(Path.TrimEndingDirectorySeparator(AppContext.BaseDirectory));
builder.Host.UseContentRoot("");
builder.WebHost.UseContentRoot(AppContext.BaseDirectory);
builder.WebHost.UseContentRoot(Path.TrimEndingDirectorySeparator(AppContext.BaseDirectory));
builder.WebHost.UseContentRoot("");
Assert.Equal(AppContext.BaseDirectory, builder.Environment.ContentRootPath);
}
[Fact]
public void WebApplicationBuilderSettingInvalidApplicationWillFailAssemblyLoadForUserSecrets()
{
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册