Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Commit

Permalink
Use RazorPagesOptions.RootDirectory when looking for page hierarchies.
Browse files Browse the repository at this point in the history
Fixes #5915
  • Loading branch information
pranavkm committed Mar 13, 2017
1 parent 4faef7a commit e1246af
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class PageActionInvokerProvider : IActionInvokerProvider
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;
Expand All @@ -53,6 +54,7 @@ public PageActionInvokerProvider(
ITempDataDictionaryFactory tempDataFactory,
IOptions<MvcOptions> mvcOptions,
IOptions<HtmlHelperOptions> htmlHelperOptions,
IOptions<RazorPagesOptions> razorPagesOptions,
IPageHandlerMethodSelector selector,
TempDataPropertyProvider propertyProvider,
RazorProject razorProject,
Expand All @@ -69,6 +71,7 @@ public PageActionInvokerProvider(
_modelMetadataProvider = modelMetadataProvider;
_tempDataFactory = tempDataFactory;
_htmlHelperOptions = htmlHelperOptions.Value;
_razorPagesOptions = razorPagesOptions.Value;
_selector = selector;
_propertyProvider = propertyProvider;
_razorProject = razorProject;
Expand Down Expand Up @@ -201,7 +204,10 @@ private PageActionInvokerCacheEntry CreateCacheEntry(
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)
Expand Down
30 changes: 30 additions & 0 deletions test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -230,6 +231,35 @@ public async Task AuthorizePage_AddsAuthorizationForSpecificPages()
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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -113,5 +114,33 @@ public async Task AuthConvention_IsAppliedOnBasePathRelativePaths_For_Folders()
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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,65 @@ public void GetPageStartFactories_FindsFullHeirarchy()
mock.Verify();
}

[Theory]
[InlineData("/Pages/Level1/")]
[InlineData("/Pages/Level1")]
public void GetPageFactories_DoesNotFindPageStartsOutsideBaseDirectory(string rootDirectory)
{
// Arrange
var descriptor = new PageActionDescriptor()
{
RelativePath = "Path1",
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 DefaultRazorProject(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()
{
Expand Down Expand Up @@ -698,7 +757,8 @@ private static PageActionInvokerProvider CreateInvokerProvider(
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>()))
Expand All @@ -720,6 +780,7 @@ private static PageActionInvokerProvider CreateInvokerProvider(
tempDataFactory.Object,
new TestOptionsManager<MvcOptions>(),
new TestOptionsManager<HtmlHelperOptions>(),
new TestOptionsManager<RazorPagesOptions>(razorPagesOptions ?? new RazorPagesOptions()),
Mock.Of<IPageHandlerMethodSelector>(),
new TempDataPropertyProvider(),
razorProject,
Expand Down
14 changes: 10 additions & 4 deletions test/Microsoft.AspNetCore.Mvc.TestCommon/TestOptionsManager.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@page
Hello from @CustomService.Value!
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@using CustomNamespace
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@page
Hello from @Path!
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello from _PageStart
10 changes: 10 additions & 0 deletions test/WebSites/RazorPagesWebSite/Services/CustomService.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}

0 comments on commit e1246af

Please sign in to comment.