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 15, 2017
1 parent de25357 commit bee1a55
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 10 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 @@ -248,6 +249,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 @@ -12,12 +12,10 @@
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;
Expand Down Expand Up @@ -574,7 +572,7 @@ public void GetPageStartFactories_FindsFullHeirarchy()
// Arrange
var descriptor = new PageActionDescriptor()
{
RelativePath = "Path1",
RelativePath = "/Views/Deeper/Index.cshtml",
FilterDescriptors = new FilterDescriptor[0],
ViewEnginePath = "/Views/Deeper/Index.cshtml"
};
Expand Down Expand Up @@ -623,13 +621,72 @@ 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 = "/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"
};
Expand Down Expand Up @@ -692,7 +749,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 @@ -714,6 +772,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 bee1a55

Please sign in to comment.