Use RazorPagesOptions.RootDirectory when looking for page hierarchies.

Fixes #5915
This commit is contained in:
Pranav K 2017-03-13 15:28:04 -07:00
parent de25357c28
commit bee1a55cff
10 changed files with 156 additions and 10 deletions

View File

@ -35,6 +35,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly ITempDataDictionaryFactory _tempDataFactory;
private readonly HtmlHelperOptions _htmlHelperOptions;
private readonly RazorPagesOptions _razorPagesOptions;
private readonly IPageHandlerMethodSelector _selector;
private readonly TempDataPropertyProvider _propertyProvider;
private readonly RazorProject _razorProject;
@ -53,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
ITempDataDictionaryFactory tempDataFactory,
IOptions<MvcOptions> mvcOptions,
IOptions<HtmlHelperOptions> htmlHelperOptions,
IOptions<RazorPagesOptions> razorPagesOptions,
IPageHandlerMethodSelector selector,
TempDataPropertyProvider propertyProvider,
RazorProject razorProject,
@ -69,6 +71,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
_modelMetadataProvider = modelMetadataProvider;
_tempDataFactory = tempDataFactory;
_htmlHelperOptions = htmlHelperOptions.Value;
_razorPagesOptions = razorPagesOptions.Value;
_selector = selector;
_propertyProvider = propertyProvider;
_razorProject = razorProject;
@ -201,7 +204,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
internal List<Func<IRazorPage>> GetPageStartFactories(CompiledPageActionDescriptor descriptor)
{
var pageStartFactories = new List<Func<IRazorPage>>();
var pageStartItems = _razorProject.FindHierarchicalItems(descriptor.ViewEnginePath, PageStartFileName);
var pageStartItems = _razorProject.FindHierarchicalItems(
_razorPagesOptions.RootDirectory,
descriptor.RelativePath,
PageStartFileName);
foreach (var item in pageStartItems)
{
if (item.Exists)

View File

@ -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.Linq;
using System.Net;
using System.Net.Http;
@ -248,6 +249,35 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal("/Login?ReturnUrl=%2FHelloWorldWithAuth", response.Headers.Location.PathAndQuery);
}
[Fact]
public async Task PageStart_IsDiscoveredWhenRootDirectoryIsNotSpecified()
{
// Test for https://github.com/aspnet/Mvc/issues/5915
//Arrange
var expected = $"Hello from _PageStart{Environment.NewLine}Hello from /Pages/WithPageStart/Index.cshtml!";
// Act
var response = await Client.GetStringAsync("/Pages/WithPageStart");
// Assert
Assert.Equal(expected, response.Trim());
}
[Fact]
public async Task PageImport_IsDiscoveredWhenRootDirectoryIsNotSpecified()
{
// Test for https://github.com/aspnet/Mvc/issues/5915
//Arrange
var expected = "Hello from CustomService!";
// Act
var response = await Client.GetStringAsync("/Pages/WithPageImport");
// Assert
Assert.Equal(expected, response.Trim());
}
private static string GetCookie(HttpResponseMessage response)
{
var setCookie = response.Headers.GetValues("Set-Cookie").ToArray();

View File

@ -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.Net;
using System.Net.Http;
using System.Threading.Tasks;
@ -113,5 +114,33 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
Assert.Equal("/Login?ReturnUrl=%2FConventions%2FAuthFolder", response.Headers.Location.PathAndQuery);
}
[Fact]
public async Task PageStart_IsDiscoveredWhenRootDirectoryIsSpecified()
{
// Test for https://github.com/aspnet/Mvc/issues/5915
//Arrange
var expected = $"Hello from _PageStart{Environment.NewLine}Hello from /Pages/WithPageStart/Index.cshtml!";
// Act
var response = await Client.GetStringAsync("/WithPageStart");
// Assert
Assert.Equal(expected, response.Trim());
}
[Fact]
public async Task PageImport_IsDiscoveredWhenRootDirectoryIsSpecified()
{
// Test for https://github.com/aspnet/Mvc/issues/5915
//Arrange
var expected = "Hello from CustomService!";
// Act
var response = await Client.GetStringAsync("/WithPageImport");
// Assert
Assert.Equal(expected, response.Trim());
}
}
}

View File

@ -12,12 +12,10 @@ using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
using Moq;
@ -574,7 +572,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
// Arrange
var descriptor = new PageActionDescriptor()
{
RelativePath = "Path1",
RelativePath = "/Views/Deeper/Index.cshtml",
FilterDescriptors = new FilterDescriptor[0],
ViewEnginePath = "/Views/Deeper/Index.cshtml"
};
@ -623,13 +621,72 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
mock.Verify();
}
[Theory]
[InlineData("/Pages/Level1/")]
[InlineData("/Pages/Level1")]
public void GetPageFactories_DoesNotFindPageStartsOutsideBaseDirectory(string rootDirectory)
{
// Arrange
var descriptor = new PageActionDescriptor()
{
RelativePath = "/Pages/Level1/Level2/Index.cshtml",
FilterDescriptors = new FilterDescriptor[0],
ViewEnginePath = "/Pages/Level1/Level2/Index.cshtml"
};
var compiledPageDescriptor = new CompiledPageActionDescriptor(descriptor)
{
PageTypeInfo = typeof(object).GetTypeInfo(),
};
var loader = new Mock<IPageLoader>();
loader.Setup(l => l.Load(It.IsAny<PageActionDescriptor>()))
.Returns(compiledPageDescriptor);
var descriptorCollection = new ActionDescriptorCollection(new[] { descriptor }, version: 1);
var actionDescriptorProvider = new Mock<IActionDescriptorCollectionProvider>();
actionDescriptorProvider.Setup(p => p.ActionDescriptors).Returns(descriptorCollection);
var fileProvider = new TestFileProvider();
fileProvider.AddFile("/_PageStart.cshtml", "page content");
fileProvider.AddFile("/Pages/_PageStart.cshtml", "page content");
fileProvider.AddFile("/Pages/Level1/_PageStart.cshtml", "page content");
fileProvider.AddFile("/Pages/Level1/Level2/_PageStart.cshtml", "page content");
fileProvider.AddFile("/Pages/Level1/Level3/_PageStart.cshtml", "page content");
var razorProject = new TestRazorProject(fileProvider);
var mock = new Mock<IRazorPageFactoryProvider>(MockBehavior.Strict);
mock.Setup(p => p.CreateFactory("/Pages/Level1/Level2/_PageStart.cshtml"))
.Returns(new RazorPageFactoryResult(() => null, new List<IChangeToken>()))
.Verifiable();
mock.Setup(p => p.CreateFactory("/Pages/Level1/_PageStart.cshtml"))
.Returns(new RazorPageFactoryResult(() => null, new List<IChangeToken>()))
.Verifiable();
var razorPageFactoryProvider = mock.Object;
var options = new RazorPagesOptions
{
RootDirectory = rootDirectory,
};
var invokerProvider = CreateInvokerProvider(
loader.Object,
actionDescriptorProvider.Object,
razorPageFactoryProvider: razorPageFactoryProvider,
razorProject: razorProject,
razorPagesOptions: options);
// Act
var factories = invokerProvider.GetPageStartFactories(compiledPageDescriptor);
// Assert
mock.Verify();
}
[Fact]
public void GetPageStartFactories_NoFactoriesForMissingFiles()
{
// Arrange
var descriptor = new PageActionDescriptor()
{
RelativePath = "Path1",
RelativePath = "/Views/Deeper/Index.cshtml",
FilterDescriptors = new FilterDescriptor[0],
ViewEnginePath = "/Views/Deeper/Index.cshtml"
};
@ -692,7 +749,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
IPageFactoryProvider pageProvider = null,
IPageModelFactoryProvider modelProvider = null,
IRazorPageFactoryProvider razorPageFactoryProvider = null,
RazorProject razorProject = null)
RazorProject razorProject = null,
RazorPagesOptions razorPagesOptions = null)
{
var tempDataFactory = new Mock<ITempDataDictionaryFactory>();
tempDataFactory.Setup(t => t.GetTempData(It.IsAny<HttpContext>()))
@ -714,6 +772,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
tempDataFactory.Object,
new TestOptionsManager<MvcOptions>(),
new TestOptionsManager<HtmlHelperOptions>(),
new TestOptionsManager<RazorPagesOptions>(razorPagesOptions ?? new RazorPagesOptions()),
Mock.Of<IPageHandlerMethodSelector>(),
new TempDataPropertyProvider(),
razorProject,

View File

@ -1,17 +1,23 @@
// 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.Linq;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc
{
public class TestOptionsManager<T> : OptionsManager<T>
where T : class, new()
public class TestOptionsManager<TOptions> : IOptions<TOptions>
where TOptions : class, new()
{
public TestOptionsManager()
: base(Enumerable.Empty<IConfigureOptions<T>>())
: this(new TOptions())
{
}
public TestOptionsManager(TOptions value)
{
Value = value;
}
public TOptions Value { get; }
}
}

View File

@ -0,0 +1,2 @@
@page
Hello from @CustomService.Value!

View File

@ -0,0 +1 @@
@using CustomNamespace

View File

@ -0,0 +1,2 @@
@page
Hello from @Path!

View File

@ -0,0 +1 @@
Hello from _PageStart

View File

@ -0,0 +1,10 @@
// 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.
namespace CustomNamespace
{
public static class CustomService
{
public static string Value => nameof(CustomService);
}
}