diff --git a/src/Microsoft.AspNet.Hosting.Abstractions/HostingEnvironmentExtensions.cs b/src/Microsoft.AspNet.Hosting.Abstractions/HostingEnvironmentExtensions.cs index c8bc3993a7..d42b40e644 100644 --- a/src/Microsoft.AspNet.Hosting.Abstractions/HostingEnvironmentExtensions.cs +++ b/src/Microsoft.AspNet.Hosting.Abstractions/HostingEnvironmentExtensions.cs @@ -91,7 +91,10 @@ namespace Microsoft.AspNet.Hosting { throw new ArgumentNullException(nameof(hostingEnvironment)); } - + if (string.IsNullOrEmpty(hostingEnvironment.WebRootPath)) + { + throw new InvalidOperationException("Can not map path because webroot path is not set"); + } if (virtualPath == null) { return hostingEnvironment.WebRootPath; diff --git a/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs b/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs index 6b1fd8c346..6b46ba7214 100644 --- a/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs +++ b/src/Microsoft.AspNet.Hosting/HostingEnvironmentExtensions.cs @@ -4,6 +4,7 @@ using System; using System.IO; using Microsoft.AspNet.FileProviders; +using Microsoft.AspNet.Hosting.Internal; using Microsoft.Extensions.Configuration; namespace Microsoft.AspNet.Hosting @@ -26,24 +27,24 @@ namespace Microsoft.AspNet.Hosting { hostingEnvironment.WebRootPath = wwwroot; } - else - { - hostingEnvironment.WebRootPath = applicationBasePath; - } } else { hostingEnvironment.WebRootPath = Path.Combine(applicationBasePath, webRoot); } - - hostingEnvironment.WebRootPath = Path.GetFullPath(hostingEnvironment.WebRootPath); - - if (!Directory.Exists(hostingEnvironment.WebRootPath)) + if (!string.IsNullOrEmpty(hostingEnvironment.WebRootPath)) { - Directory.CreateDirectory(hostingEnvironment.WebRootPath); + hostingEnvironment.WebRootPath = Path.GetFullPath(hostingEnvironment.WebRootPath); + if (!Directory.Exists(hostingEnvironment.WebRootPath)) + { + Directory.CreateDirectory(hostingEnvironment.WebRootPath); + } + hostingEnvironment.WebRootFileProvider = new PhysicalFileProvider(hostingEnvironment.WebRootPath); + } + else + { + hostingEnvironment.WebRootFileProvider = new NullFileProvider(); } - hostingEnvironment.WebRootFileProvider = new PhysicalFileProvider(hostingEnvironment.WebRootPath); - var environmentName = options.Environment; hostingEnvironment.EnvironmentName = environmentName ?? hostingEnvironment.EnvironmentName; diff --git a/src/Microsoft.AspNet.Hosting/Internal/NullFileProvider.cs b/src/Microsoft.AspNet.Hosting/Internal/NullFileProvider.cs new file mode 100644 index 0000000000..73f0bebc93 --- /dev/null +++ b/src/Microsoft.AspNet.Hosting/Internal/NullFileProvider.cs @@ -0,0 +1,82 @@ +// 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 Microsoft.AspNet.FileProviders; +using Microsoft.Extensions.Primitives; + +namespace Microsoft.AspNet.Hosting.Internal +{ + internal class NullFileProvider : IFileProvider + { + public IDirectoryContents GetDirectoryContents(string subpath) + { + return new NullDirectoryContents(); + } + + public IFileInfo GetFileInfo(string subpath) + { + return new NullFileInfo(subpath); + } + + public IChangeToken Watch(string filter) + { + return new NullChangeToken(); + } + + private class NullDirectoryContents : IDirectoryContents + { + public bool Exists => false; + + public IEnumerator GetEnumerator() + { + yield break; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + + internal class NullFileInfo : IFileInfo + { + public NullFileInfo(string name) + { + Name = name; + } + + public bool Exists => false; + + public bool IsDirectory => false; + + public DateTimeOffset LastModified => DateTimeOffset.MinValue; + + public long Length => -1; + + public string Name { get; } + + public string PhysicalPath => null; + + public Stream CreateReadStream() + { + throw new FileNotFoundException(string.Format($"{nameof(NullFileProvider)} does not support reading files.", Name)); + } + } + + private class NullChangeToken : IChangeToken + { + public bool HasChanged => false; + + public bool ActiveChangeCallbacks => false; + + public IDisposable RegisterChangeCallback(Action callback, object state) + { + throw new NotSupportedException($"{nameof(NullFileProvider)} does not support registering change notifications."); + } + } + } +} diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs index 1268e981fe..2017193a16 100644 --- a/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEngineTests.cs @@ -464,6 +464,9 @@ namespace Microsoft.AspNet.Hosting using (engine.Start()) { var env = engine.ApplicationServices.GetRequiredService(); + // MapPath requires webroot to be set, we don't care + // about file provider so just set it here + env.WebRootPath = ""; var mappedPath = env.MapPath(virtualPath); expectedSuffix = expectedSuffix.Replace('/', Path.DirectorySeparatorChar); Assert.Equal(Path.Combine(env.WebRootPath, expectedSuffix), mappedPath); diff --git a/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs b/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs new file mode 100644 index 0000000000..44ab8996e2 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/HostingEnvironmentExtensionsTests.cs @@ -0,0 +1,71 @@ +// 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.IO; +using Microsoft.AspNet.FileProviders; +using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Hosting.Internal; +using Microsoft.Extensions.Configuration; +using Xunit; + +namespace Microsoft.AspNet.Hosting.Tests +{ + public class HostingEnvironmentExtensionsTests + { + [Fact] + public void SetsFullPathToWwwroot() + { + var env = new HostingEnvironment(); + + env.Initialize(".", new WebHostOptions() {WebRoot = "testroot"}, null); + + Assert.Equal(Path.GetFullPath("testroot"), env.WebRootPath); + Assert.IsAssignableFrom(env.WebRootFileProvider); + } + + [Fact] + public void DefaultsToWwwrootSubdir() + { + var env = new HostingEnvironment(); + + env.Initialize("testroot", new WebHostOptions(), null); + + Assert.Equal(Path.GetFullPath(Path.Combine("testroot","wwwroot")), env.WebRootPath); + Assert.IsAssignableFrom(env.WebRootFileProvider); + } + + [Fact] + public void DefaultsToNullFileProvider() + { + var env = new HostingEnvironment(); + + env.Initialize(Path.Combine("testroot", "wwwroot"), new WebHostOptions(), null); + + Assert.Null(env.WebRootPath); + Assert.IsAssignableFrom(env.WebRootFileProvider); + } + + [Fact] + public void SetsConfiguration() + { + var config = new ConfigurationBuilder().Build(); + var env = new HostingEnvironment(); + + env.Initialize(".", new WebHostOptions(), config); + + Assert.Same(config, env.Configuration); + } + + [Fact] + public void OverridesEnvironmentFromConfig() + { + var env = new HostingEnvironment(); + env.EnvironmentName = "SomeName"; + + env.Initialize(".", new WebHostOptions() { Environment = "NewName" }, null); + + Assert.Equal("NewName", env.EnvironmentName); + } + + } +} diff --git a/test/Microsoft.AspNet.Hosting.Tests/testroot/wwwroot/README b/test/Microsoft.AspNet.Hosting.Tests/testroot/wwwroot/README new file mode 100644 index 0000000000..4b906ff4a8 --- /dev/null +++ b/test/Microsoft.AspNet.Hosting.Tests/testroot/wwwroot/README @@ -0,0 +1 @@ +This file is here to keep directories needed by tests. Do no remove it. \ No newline at end of file diff --git a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs index 3116e549fa..9ca048c9e0 100644 --- a/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs +++ b/test/Microsoft.AspNet.TestHost.Tests/TestServerTests.cs @@ -305,16 +305,6 @@ namespace Microsoft.AspNet.TestHost Assert.Equal("CreateInvokesApp", result); } - [Fact] - public void WebRootCanBeResolvedWhenNotInTheConfig() - { - TestServer server = TestServer.Create(app => - { - var env = app.ApplicationServices.GetRequiredService(); - Assert.Equal(Directory.GetCurrentDirectory(), env.WebRootPath); - }); - } - [Fact] public async Task DisposeStreamIgnored() {