This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The View Engine now needs to know about pages :(. This isn't ideal but the view engine needs to know what set of search paths to use. This was already hardcoded for controllers vs controllers + areas. It felt right to further hardcode instead of introduce a wierd abstraction that we only use. Additionally pages use a view location expander to implement an ascending directory search.
- Loading branch information
Showing
17 changed files
with
547 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageViewLocationExpander.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// 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.Collections.Generic; | ||
using Microsoft.AspNetCore.Mvc.Razor; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure | ||
{ | ||
public class PageViewLocationExpander : IViewLocationExpander | ||
{ | ||
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) | ||
{ | ||
if (string.IsNullOrEmpty(context.PageName)) | ||
{ | ||
// Not a page - just act natural. | ||
return viewLocations; | ||
} | ||
|
||
return ExpandPageHierarchy(); | ||
|
||
IEnumerable<string> ExpandPageHierarchy() | ||
{ | ||
foreach (var location in viewLocations) | ||
{ | ||
// For pages, we only handle the 'page' token when it's surrounded by slashes. | ||
// | ||
// Explanation: | ||
// We need the ability to 'collapse' the segment which requires us to understand slashes. | ||
// Imagine a path like /{1}/{0} - we might end up with //{0} if we don't do *something* with | ||
// the slashes. Instead of picking on (leading or trailing), we choose both. This seems | ||
// less arbitrary. | ||
// | ||
// | ||
// So given a Page like /Account/Manage/Index using /Pages as the root, and the default set of | ||
// search paths, this will produce the expanded paths: | ||
// | ||
// /Pages/Account/Manage/{0}.cshtml | ||
// /Pages/Account/{0}.cshtml | ||
// /Pages/{0}.cshtml | ||
// /Views/Shared/{0}.cshtml | ||
|
||
if (!location.Contains("/{1}/")) | ||
{ | ||
// If the location doesn't have the 'page' replacement token just return it as-is. | ||
yield return location; | ||
continue; | ||
} | ||
|
||
// For locations with the 'page' token - expand them into an ascending directory search, | ||
// but only up to the pages root. | ||
// | ||
// This is easy because the 'page' token already trims the root directory. | ||
var end = context.PageName.Length; | ||
|
||
while (end > 0 && (end = context.PageName.LastIndexOf('/', end - 1)) != -1) | ||
{ | ||
// PageName always starts with `/` | ||
yield return location.Replace("/{1}/", context.PageName.Substring(0, end + 1)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public void PopulateValues(ViewLocationExpanderContext context) | ||
{ | ||
// The value we care about - 'page' is already part of the system. We don't need to add it manually. | ||
} | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesRazorViewEngineOptionsSetup.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// 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.Diagnostics; | ||
using Microsoft.AspNetCore.Mvc.Razor; | ||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal | ||
{ | ||
public class RazorPagesRazorViewEngineOptionsSetup : IConfigureOptions<RazorViewEngineOptions> | ||
{ | ||
private readonly IOptions<RazorPagesOptions> _pagesOptions; | ||
|
||
public RazorPagesRazorViewEngineOptionsSetup(IOptions<RazorPagesOptions> pagesOptions) | ||
{ | ||
_pagesOptions = pagesOptions; | ||
} | ||
|
||
public void Configure(RazorViewEngineOptions options) | ||
{ | ||
Debug.Assert(_pagesOptions.Value.RootDirectory.Length > 0); | ||
|
||
if (_pagesOptions.Value.RootDirectory == "/") | ||
{ | ||
options.PageViewLocationFormats.Add("/{1}/{0}" + RazorViewEngine.ViewExtension); | ||
} | ||
else | ||
{ | ||
options.PageViewLocationFormats.Add(_pagesOptions.Value.RootDirectory + "/{1}/{0}" + RazorViewEngine.ViewExtension); | ||
} | ||
|
||
options.PageViewLocationFormats.Add("/Views/Shared/{0}" + RazorViewEngine.ViewExtension); | ||
|
||
options.ViewLocationExpanders.Add(new PageViewLocationExpander()); | ||
} | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesViewSearchTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// 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.Generic; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests | ||
{ | ||
public class RazorPagesViewSearchTest : IClassFixture<MvcTestFixture<RazorPagesWebSite.Startup>> | ||
{ | ||
public RazorPagesViewSearchTest(MvcTestFixture<RazorPagesWebSite.Startup> fixture) | ||
{ | ||
Client = fixture.Client; | ||
} | ||
|
||
public HttpClient Client { get; } | ||
|
||
[Fact] | ||
public async Task Page_CanFindPartial_InCurrentDirectory() | ||
{ | ||
// Arrange & Act | ||
var content = await Client.GetStringAsync("http://localhost/Pages/ViewSearch?partial=_Sibling"); | ||
|
||
// Assert | ||
Assert.Equal("Hello from sibling", content.Trim()); | ||
} | ||
|
||
[Fact] | ||
public async Task Page_CanFindPartial_InParentDirectory() | ||
{ | ||
// Arrange & Act | ||
var content = await Client.GetStringAsync("http://localhost/Pages/ViewSearch?partial=_Parent"); | ||
|
||
// Assert | ||
Assert.Equal("Hello from parent", content.Trim()); | ||
} | ||
|
||
[Fact] | ||
public async Task Page_CanFindPartial_InRootDirectory() | ||
{ | ||
// Arrange & Act | ||
var content = await Client.GetStringAsync("http://localhost/Pages/ViewSearch?partial=_Root"); | ||
|
||
// Assert | ||
Assert.Equal("Hello from root", content.Trim()); | ||
} | ||
|
||
[Fact] | ||
public async Task Page_CanFindPartial_InViewsSharedDirectory() | ||
{ | ||
// Arrange & Act | ||
var content = await Client.GetStringAsync("http://localhost/Pages/ViewSearch?partial=_Shared"); | ||
|
||
// Assert | ||
Assert.Equal("Hello from shared", content.Trim()); | ||
} | ||
} | ||
} |
Oops, something went wrong.