diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/FileSystemRazorProject.cs b/src/Microsoft.AspNetCore.Razor.Evolution/FileSystemRazorProject.cs
index 1d794919b0..bf51f43d02 100644
--- a/src/Microsoft.AspNetCore.Razor.Evolution/FileSystemRazorProject.cs
+++ b/src/Microsoft.AspNetCore.Razor.Evolution/FileSystemRazorProject.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -25,7 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(root));
}
- Root = root.TrimEnd('/', '\\');
+ Root = root.Replace('\\', '/').TrimEnd('/');
}
///
@@ -36,10 +35,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
///
public override IEnumerable EnumerateItems(string basePath)
{
- EnsureValidPath(basePath);
-
- Debug.Assert(basePath.StartsWith("/"));
- var absoluteBasePath = Path.Combine(Root, basePath.Substring(1));
+ var absoluteBasePath = NormalizeAndEnsureValidPath(basePath);
var directory = new DirectoryInfo(absoluteBasePath);
if (!directory.Exists)
@@ -53,17 +49,38 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
var relativePath = file.FullName.Substring(absoluteBasePath.Length).Replace(Path.DirectorySeparatorChar, '/');
return new FileSystemRazorProjectItem(basePath, relativePath, file);
- });
+ });
}
///
public override RazorProjectItem GetItem(string path)
{
- EnsureValidPath(path);
+ var absolutePath = NormalizeAndEnsureValidPath(path);
- Debug.Assert(path.StartsWith("/"));
- var absolutePath = Path.Combine(Root, path.Substring(1));
return new FileSystemRazorProjectItem("/", path, new FileInfo(absolutePath));
}
+
+ protected override string NormalizeAndEnsureValidPath(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(path));
+ }
+
+ var absolutePath = path;
+ if (!absolutePath.StartsWith(Root, StringComparison.OrdinalIgnoreCase))
+ {
+ if (path[0] == '/' || path[0] == '\\')
+ {
+ path = path.Substring(1);
+ }
+
+ absolutePath = Path.Combine(Root, path);
+ }
+
+ absolutePath = absolutePath.Replace('\\', '/');
+
+ return absolutePath;
+ }
}
}
diff --git a/src/Microsoft.AspNetCore.Razor.Evolution/RazorProject.cs b/src/Microsoft.AspNetCore.Razor.Evolution/RazorProject.cs
index 536e252090..dbda49932f 100644
--- a/src/Microsoft.AspNetCore.Razor.Evolution/RazorProject.cs
+++ b/src/Microsoft.AspNetCore.Razor.Evolution/RazorProject.cs
@@ -59,8 +59,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
///
public virtual IEnumerable FindHierarchicalItems(string basePath, string path, string fileName)
{
- EnsureValidPath(basePath);
- EnsureValidPath(path);
+ basePath = NormalizeAndEnsureValidPath(basePath);
+ path = NormalizeAndEnsureValidPath(path);
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(fileName));
@@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
/// Performs validation for paths passed to methods of .
///
/// The path to validate.
- protected virtual void EnsureValidPath(string path)
+ protected virtual string NormalizeAndEnsureValidPath(string path)
{
if (string.IsNullOrEmpty(path))
{
@@ -120,6 +120,8 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
throw new ArgumentException(Resources.RazorProject_PathMustStartWithForwardSlash, nameof(path));
}
+
+ return path;
}
}
}
diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/FileSystemRazorProjectTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/FileSystemRazorProjectTest.cs
index d9d21dc1f6..945ea2cbb3 100644
--- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/FileSystemRazorProjectTest.cs
+++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/FileSystemRazorProjectTest.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
+using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Evolution
@@ -12,6 +13,57 @@ namespace Microsoft.AspNetCore.Razor.Evolution
private static string TestFolder { get; } =
Path.Combine(TestProject.GetProjectDirectory(), "TestFiles", "FileSystemRazorProject");
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void NormalizeAndEnsureValidPath_ThrowsIfPathIsNullOrEmpty(string path)
+ {
+ // Arrange
+ var project = new TestFileSystemRazorProject("C:/some/test/path/root");
+
+ // Act and Assert
+ ExceptionAssert.ThrowsArgumentNullOrEmptyString(() => project.NormalizeAndEnsureValidPath(path), "path");
+ }
+
+ [Fact]
+ public void NormalizeAndEnsureValidPath_NormalizesToAbsolutePath()
+ {
+ // Arrange
+ var project = new TestFileSystemRazorProject("C:/some/test/path/root");
+
+ // Act
+ var absolutePath = project.NormalizeAndEnsureValidPath("file.cshtml");
+
+ // Assert
+ Assert.Equal("C:/some/test/path/root/file.cshtml", absolutePath);
+ }
+
+ [Fact]
+ public void NormalizeAndEnsureValidPath_NormalizesToAbsolutePathWithoutForwardSlash()
+ {
+ // Arrange
+ var project = new TestFileSystemRazorProject("C:/some/test/path/root");
+
+ // Act
+ var absolutePath = project.NormalizeAndEnsureValidPath("/file.cshtml");
+
+ // Assert
+ Assert.Equal("C:/some/test/path/root/file.cshtml", absolutePath);
+ }
+
+ [Fact]
+ public void NormalizeAndEnsureValidPath_NormalizesToForwardSlashes()
+ {
+ // Arrange
+ var project = new TestFileSystemRazorProject(@"C:\some\test\path\root");
+
+ // Act
+ var absolutePath = project.NormalizeAndEnsureValidPath(@"something\file.cshtml");
+
+ // Assert
+ Assert.Equal("C:/some/test/path/root/something/file.cshtml", absolutePath);
+ }
+
[Fact]
public void EnumerateItems_DiscoversAllCshtmlFiles()
{
@@ -104,5 +156,14 @@ namespace Microsoft.AspNetCore.Razor.Evolution
// Assert
Assert.False(file.Exists);
}
+
+ private class TestFileSystemRazorProject : FileSystemRazorProject
+ {
+ public TestFileSystemRazorProject(string root) : base(root)
+ {
+ }
+
+ public new string NormalizeAndEnsureValidPath(string path) => base.NormalizeAndEnsureValidPath(path);
+ }
}
}
diff --git a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorProjectTest.cs b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorProjectTest.cs
index 6e433de850..0222427e5b 100644
--- a/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorProjectTest.cs
+++ b/test/Microsoft.AspNetCore.Razor.Evolution.Test/RazorProjectTest.cs
@@ -11,30 +11,43 @@ namespace Microsoft.AspNetCore.Razor.Evolution
{
public class RazorProjectTest
{
+ [Fact]
+ public void NormalizeAndEnsureValidPath_DoesNotModifyPath()
+ {
+ // Arrange
+ var project = new TestRazorProject(new Dictionary());
+
+ // Act
+ var path = project.NormalizeAndEnsureValidPath("/Views/Home/Index.cshtml");
+
+ // Assert
+ Assert.Equal("/Views/Home/Index.cshtml", path);
+ }
+
[Theory]
[InlineData(null)]
[InlineData("")]
- public void EnsureValidPath_ThrowsIfPathIsNullOrEmpty(string path)
+ public void NormalizeAndEnsureValidPath_ThrowsIfPathIsNullOrEmpty(string path)
{
// Arrange
var project = new TestRazorProject(new Dictionary());
// Act and Assert
- ExceptionAssert.ThrowsArgumentNullOrEmptyString(() => project.EnsureValidPath(path), "path");
+ ExceptionAssert.ThrowsArgumentNullOrEmptyString(() => project.NormalizeAndEnsureValidPath(path), "path");
}
[Theory]
[InlineData("foo")]
[InlineData("~/foo")]
[InlineData("\\foo")]
- public void EnsureValidPath_ThrowsIfPathDoesNotStartWithForwardSlash(string path)
+ public void NormalizeAndEnsureValidPath_ThrowsIfPathDoesNotStartWithForwardSlash(string path)
{
// Arrange
var project = new TestRazorProject(new Dictionary());
// Act and Assert
ExceptionAssert.ThrowsArgument(
- () => project.EnsureValidPath(path),
+ () => project.NormalizeAndEnsureValidPath(path),
"path",
"Path must begin with a forward slash '/'.");
}
@@ -338,7 +351,7 @@ namespace Microsoft.AspNetCore.Razor.Evolution
return item;
}
- public new void EnsureValidPath(string path) => base.EnsureValidPath(path);
+ public new string NormalizeAndEnsureValidPath(string path) => base.NormalizeAndEnsureValidPath(path);
}
}
}