diff --git a/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs b/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs index 74cf50ec74..b6e5e8071a 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs +++ b/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.IO; using Microsoft.AspNet.FileProviders; using Microsoft.Extensions.Configuration; @@ -9,14 +10,14 @@ namespace Microsoft.AspNet.Hosting { public static class HostingEnvironmentExtensions { - private const string OldEnvironmentKey = "ASPNET_ENV"; - private const string EnvironmentKey = "Hosting:Environment"; - - private const string WebRootKey = "webroot"; - - public static void Initialize(this IHostingEnvironment hostingEnvironment, string applicationBasePath, IConfiguration config) + public static void Initialize(this IHostingEnvironment hostingEnvironment, string applicationBasePath, WebHostOptions options) { - var webRoot = config?[WebRootKey]; + if (options == null) + { + throw new ArgumentNullException(nameof(options)); + } + + var webRoot = options.WebRoot; if (webRoot == null) { // Default to /wwwroot if it exists. @@ -43,7 +44,7 @@ namespace Microsoft.AspNet.Hosting } hostingEnvironment.WebRootFileProvider = new PhysicalFileProvider(hostingEnvironment.WebRootPath); - var environmentName = config?[EnvironmentKey] ?? config?[OldEnvironmentKey]; + var environmentName = options.Environment; hostingEnvironment.EnvironmentName = environmentName ?? hostingEnvironment.EnvironmentName; } } diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs index c504e6d0e3..4b304c152a 100644 --- a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs +++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs @@ -24,11 +24,11 @@ namespace Microsoft.AspNet.Hosting.Internal { // This is defined by IIS's HttpPlatformHandler. private static readonly string ServerPort = "HTTP_PLATFORM_PORT"; - private static readonly string DetailedErrors = "Hosting:DetailedErrors"; private readonly IServiceCollection _applicationServiceCollection; private readonly IStartupLoader _startupLoader; private readonly ApplicationLifetime _applicationLifetime; + private readonly WebHostOptions _options; private readonly IConfiguration _config; private readonly bool _captureStartupErrors; @@ -47,6 +47,7 @@ namespace Microsoft.AspNet.Hosting.Internal public HostingEngine( IServiceCollection appServices, IStartupLoader startupLoader, + WebHostOptions options, IConfiguration config, bool captureStartupErrors) { @@ -66,6 +67,7 @@ namespace Microsoft.AspNet.Hosting.Internal } _config = config; + _options = options; _applicationServiceCollection = appServices; _startupLoader = startupLoader; _captureStartupErrors = captureStartupErrors; @@ -226,9 +228,7 @@ namespace Microsoft.AspNet.Hosting.Internal // Generate an HTML error page. var runtimeEnv = _applicationServices.GetRequiredService(); var hostingEnv = _applicationServices.GetRequiredService(); - var showDetailedErrors = hostingEnv.IsDevelopment() - || string.Equals("true", _config[DetailedErrors], StringComparison.OrdinalIgnoreCase) - || string.Equals("1", _config[DetailedErrors], StringComparison.OrdinalIgnoreCase); + var showDetailedErrors = hostingEnv.IsDevelopment() || _options.DetailedErrors; var errorBytes = StartupExceptionPage.GenerateErrorHtml(showDetailedErrors, runtimeEnv, ex); return context => diff --git a/src/Microsoft.AspNet.Hosting/WebApplication.cs b/src/Microsoft.AspNet.Hosting/WebApplication.cs index 7d77a911db..33a834b183 100644 --- a/src/Microsoft.AspNet.Hosting/WebApplication.cs +++ b/src/Microsoft.AspNet.Hosting/WebApplication.cs @@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Hosting public class WebApplication { private const string HostingJsonFile = "hosting.json"; + private const string EnvironmentVariablesPrefix = "ASPNET_"; private const string ConfigFileKey = "config"; public static void Run(string[] args) @@ -40,12 +41,7 @@ namespace Microsoft.AspNet.Hosting var tempBuilder = new ConfigurationBuilder().AddCommandLine(args); var tempConfig = tempBuilder.Build(); var configFilePath = tempConfig[ConfigFileKey] ?? HostingJsonFile; - - var config = new ConfigurationBuilder() - .AddJsonFile(configFilePath, optional: true) - .AddEnvironmentVariables() - .AddCommandLine(args) - .Build(); + var config = LoadHostingConfiguration(configFilePath, args); var hostBuilder = new WebHostBuilder(config, captureStartupErrors: true); if (startupType != null) @@ -81,5 +77,14 @@ namespace Microsoft.AspNet.Hosting appLifetime.ApplicationStopping.WaitHandle.WaitOne(); } } + + internal static IConfiguration LoadHostingConfiguration(string configJsonPath, string[] args) + { + return new ConfigurationBuilder() + .AddJsonFile(configJsonPath, optional: true) + .AddEnvironmentVariables(prefix: EnvironmentVariablesPrefix) + .AddCommandLine(args) + .Build(); + } } } diff --git a/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs b/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs index 26f5938eba..a26796412f 100644 --- a/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs +++ b/src/Microsoft.AspNet.Hosting/WebHostBuilder.cs @@ -21,15 +21,10 @@ namespace Microsoft.AspNet.Hosting { public class WebHostBuilder { - public const string OldApplicationKey = "app"; - public const string ApplicationKey = "Hosting:Application"; - - public const string OldServerKey = "server"; - public const string ServerKey = "Hosting:Server"; - private readonly IHostingEnvironment _hostingEnvironment; private readonly ILoggerFactory _loggerFactory; private readonly IConfiguration _config; + private readonly WebHostOptions _options; private Action _configureServices; @@ -64,6 +59,7 @@ namespace Microsoft.AspNet.Hosting _hostingEnvironment = new HostingEnvironment(); _loggerFactory = new LoggerFactory(); _config = config; + _options = new WebHostOptions(config); _captureStartupErrors = captureStartupErrors; } @@ -130,18 +126,18 @@ namespace Microsoft.AspNet.Hosting var appEnvironment = hostingContainer.GetRequiredService(); var startupLoader = hostingContainer.GetRequiredService(); - _hostingEnvironment.Initialize(appEnvironment.ApplicationBasePath, _config); - var engine = new HostingEngine(hostingServices, startupLoader, _config, _captureStartupErrors); + _hostingEnvironment.Initialize(appEnvironment.ApplicationBasePath, _options); + var engine = new HostingEngine(hostingServices, startupLoader, _options, _config, _captureStartupErrors); // Only one of these should be set, but they are used in priority engine.Server = _server; engine.ServerFactory = _serverFactory; - engine.ServerFactoryLocation = _config[ServerKey] ?? _config[OldServerKey] ?? _serverFactoryLocation; + engine.ServerFactoryLocation = _options.Server ?? _serverFactoryLocation; // Only one of these should be set, but they are used in priority engine.Startup = _startup; engine.StartupType = _startupType; - engine.StartupAssemblyName = _startupAssemblyName ?? _config[ApplicationKey] ?? _config[OldApplicationKey] ?? appEnvironment.ApplicationName; + engine.StartupAssemblyName = _startupAssemblyName ?? _options.Application ?? appEnvironment.ApplicationName; return engine; } diff --git a/src/Microsoft.AspNet.Hosting/WebHostOptions.cs b/src/Microsoft.AspNet.Hosting/WebHostOptions.cs new file mode 100644 index 0000000000..89a0aad6bc --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/WebHostOptions.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.AspNet.Hosting +{ + public class WebHostOptions + { + private const string ApplicationKey = "app"; + private const string DetailedErrorsKey = "detailedErrors"; + private const string EnvironmentKey = "environment"; + private const string ServerKey = "server"; + private const string WebRootKey = "webroot"; + private const string OldEnvironmentKey = "ENV"; + + public WebHostOptions() + { + } + + public WebHostOptions(IConfiguration configuration) + { + if (configuration == null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + Application = configuration[ApplicationKey]; + DetailedErrors = string.Equals("true", configuration[DetailedErrorsKey], StringComparison.OrdinalIgnoreCase) + || string.Equals("1", configuration[DetailedErrorsKey], StringComparison.OrdinalIgnoreCase); + Environment = configuration[EnvironmentKey] ?? configuration[OldEnvironmentKey]; + Server = configuration[ServerKey]; + WebRoot = configuration[WebRootKey]; + } + + public string Application { get; set; } + + public bool DetailedErrors { get; set; } + + public string Environment { get; set; } + + public string Server { get; set; } + + public string WebRoot { get; set; } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs index 0e0655ecac..a31fbd5d43 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs @@ -98,7 +98,7 @@ namespace Microsoft.AspNet.Hosting { var vals = new Dictionary { - { "Hosting:Server", "Microsoft.AspNet.Hosting.Tests" } + { "Server", "Microsoft.AspNet.Hosting.Tests" } }; var builder = new ConfigurationBuilder() @@ -114,7 +114,7 @@ namespace Microsoft.AspNet.Hosting { var vals = new Dictionary { - { "Hosting:Server", "Microsoft.AspNet.Hosting.Tests" }, + { "Server", "Microsoft.AspNet.Hosting.Tests" }, { "HTTP_PLATFORM_PORT", "abc123" } }; @@ -132,7 +132,7 @@ namespace Microsoft.AspNet.Hosting { var vals = new Dictionary { - { "Hosting:Server", "Microsoft.AspNet.Hosting.Tests" } + { "Server", "Microsoft.AspNet.Hosting.Tests" } }; var builder = new ConfigurationBuilder() @@ -250,7 +250,9 @@ namespace Microsoft.AspNet.Hosting { var vals = new Dictionary { - { "ASPNET_ENV", "Staging" } + // Old key is actualy ASPNET_ENV but WebHostConfiguration expects environment + // variable names stripped from ASPNET_ prefix so using just ENV here + { "ENV", "Staging" } }; var builder = new ConfigurationBuilder() @@ -267,7 +269,7 @@ namespace Microsoft.AspNet.Hosting { var vals = new Dictionary { - { "Hosting:Environment", "Staging" } + { "Environment", "Staging" } }; var builder = new ConfigurationBuilder() diff --git a/test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs b/test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs index 3ab61daf96..db801c2f4d 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/WebHostBuilderTests.cs @@ -129,7 +129,7 @@ namespace Microsoft.AspNet.Hosting var vals = new Dictionary { { "server", "Microsoft.AspNet.Hosting.Tests" }, - { "Hosting:DetailedErrors", "true" }, + { "DetailedErrors", "true" }, }; var builder = new ConfigurationBuilder() .AddInMemoryCollection(vals); diff --git a/test/Microsoft.AspNet.Hosting.Tests/WebHostConfigurationsTests.cs b/test/Microsoft.AspNet.Hosting.Tests/WebHostConfigurationsTests.cs new file mode 100644 index 0000000000..ea3b314bbd --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/WebHostConfigurationsTests.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Builder.Internal; +using Microsoft.AspNet.Hosting.Fakes; +using Microsoft.AspNet.Hosting.Startup; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.OptionsModel; +using Xunit; + +namespace Microsoft.AspNet.Hosting.Tests +{ + public class WebHostConfigurationTests + { + [Fact] + public void ReadsParametersCorrectly() + { + var parameters = new Dictionary() + { + {"webroot", "wwwroot"}, + {"server", "Microsoft.AspNet.Server.Kestrel"}, + {"app", "MyProjectReference"}, + {"environment", "Development"}, + {"detailederrors", "true"}, + }; + + var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); + + Assert.Equal("wwwroot", config.WebRoot); + Assert.Equal("Microsoft.AspNet.Server.Kestrel", config.Server); + Assert.Equal("MyProjectReference", config.Application); + Assert.Equal("Development", config.Environment); + Assert.Equal(true, config.DetailedErrors); + } + + [Fact] + public void ReadsOldEnvKey() + { + var parameters = new Dictionary() { { "ENV", "Development" } }; + var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); + + Assert.Equal("Development", config.Environment); + } + + [Theory] + [InlineData("1", true)] + [InlineData("0", false)] + public void AllowsNumberForDetailedErrors(string value, bool expected) + { + var parameters = new Dictionary() { { "detailedErrors", value } }; + var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); + + Assert.Equal(expected, config.DetailedErrors); + } + } +}