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.
Fixes #5353
- Loading branch information
Showing
17 changed files
with
938 additions
and
21 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
17 changes: 17 additions & 0 deletions
17
src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationModels/IPageModelConvention.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,17 @@ | ||
// 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 Microsoft.AspNetCore.Mvc.ApplicationModels | ||
{ | ||
/// <summary> | ||
/// Allows customization of the of the <see cref="PageModel"/>. | ||
/// </summary> | ||
public interface IPageModelConvention | ||
{ | ||
/// <summary> | ||
/// Called to apply the convention to the <see cref="PageModel"/>. | ||
/// </summary> | ||
/// <param name="model">The <see cref="PageModel"/>.</param> | ||
void Apply(PageModel model); | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationModels/PageModels.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,86 @@ | ||
// 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 Microsoft.AspNetCore.Mvc.Filters; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels | ||
{ | ||
/// <summary> | ||
/// Application model component for RazorPages. | ||
/// </summary> | ||
public class PageModel | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of <see cref="PageModel"/>. | ||
/// </summary> | ||
/// <param name="relativePath">The application relative path of the page.</param> | ||
/// <param name="viewEnginePath">The path relative to the base path for page discovery.</param> | ||
public PageModel(string relativePath, string viewEnginePath) | ||
{ | ||
if (relativePath == null) | ||
{ | ||
throw new ArgumentNullException(nameof(relativePath)); | ||
} | ||
|
||
if (viewEnginePath == null) | ||
{ | ||
throw new ArgumentNullException(nameof(viewEnginePath)); | ||
} | ||
|
||
RelativePath = relativePath; | ||
ViewEnginePath = viewEnginePath; | ||
|
||
Filters = new List<IFilterMetadata>(); | ||
Properties = new Dictionary<object, object>(); | ||
Selectors = new List<SelectorModel>(); | ||
} | ||
|
||
/// <summary> | ||
/// A copy constructor for <see cref="PageModel"/>. | ||
/// </summary> | ||
/// <param name="other">The <see cref="PageModel"/> to copy from.</param> | ||
public PageModel(PageModel other) | ||
{ | ||
if (other == null) | ||
{ | ||
throw new ArgumentNullException(nameof(other)); | ||
} | ||
|
||
RelativePath = other.RelativePath; | ||
ViewEnginePath = other.ViewEnginePath; | ||
|
||
Filters = new List<IFilterMetadata>(other.Filters); | ||
Properties = new Dictionary<object, object>(other.Properties); | ||
|
||
Selectors = new List<SelectorModel>(other.Selectors.Select(m => new SelectorModel(m))); | ||
} | ||
|
||
/// <summary> | ||
/// Gets or sets the application root relative path for the page. | ||
/// </summary> | ||
public string RelativePath { get; } | ||
|
||
/// <summary> | ||
/// Gets or sets the path relative to the base path for page discovery. | ||
/// </summary> | ||
public string ViewEnginePath { get; } | ||
|
||
/// <summary> | ||
/// Gets or sets the applicable <see cref="IFilterMetadata"/> instances. | ||
/// </summary> | ||
public IList<IFilterMetadata> Filters { get; } | ||
|
||
/// <summary> | ||
/// Stores arbitrary metadata properties associated with the <see cref="PageModel"/>. | ||
/// </summary> | ||
public IDictionary<object, object> Properties { get; } | ||
|
||
/// <summary> | ||
/// Gets or sets the <see cref="SelectorModel"/> instances. | ||
/// </summary> | ||
public IList<SelectorModel> Selectors { get; } | ||
} | ||
} |
127 changes: 127 additions & 0 deletions
127
src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.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,127 @@ | ||
// 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 Microsoft.AspNetCore.Mvc.Abstractions; | ||
using Microsoft.AspNetCore.Mvc.ApplicationModels; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.Mvc.Routing; | ||
using Microsoft.AspNetCore.Razor.Evolution; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure | ||
{ | ||
public class PageActionDescriptorProvider : IActionDescriptorProvider | ||
{ | ||
private static readonly string IndexFileName = "Index.cshtml"; | ||
private readonly RazorProject _project; | ||
private readonly MvcOptions _mvcOptions; | ||
private readonly RazorPagesOptions _pagesOptions; | ||
|
||
public PageActionDescriptorProvider( | ||
RazorProject project, | ||
IOptions<MvcOptions> mvcOptionsAccessor, | ||
IOptions<RazorPagesOptions> pagesOptionsAccessor) | ||
{ | ||
_project = project; | ||
_mvcOptions = mvcOptionsAccessor.Value; | ||
_pagesOptions = pagesOptionsAccessor.Value; | ||
} | ||
|
||
public int Order { get; set; } | ||
|
||
public void OnProvidersExecuting(ActionDescriptorProviderContext context) | ||
{ | ||
foreach (var item in _project.EnumerateItems("/")) | ||
{ | ||
if (item.Filename.StartsWith("_")) | ||
{ | ||
// Pages like _PageImports should not be routable. | ||
continue; | ||
} | ||
|
||
string template; | ||
if (!PageDirectiveFeature.TryGetRouteTemplate(item, out template)) | ||
{ | ||
// .cshtml pages without @page are not RazorPages. | ||
continue; | ||
} | ||
|
||
if (AttributeRouteModel.IsOverridePattern(template)) | ||
{ | ||
throw new InvalidOperationException(string.Format( | ||
Resources.PageActionDescriptorProvider_RouteTemplateCannotBeOverrideable, | ||
item.Path)); | ||
} | ||
|
||
AddActionDescriptors(context.Results, item, template); | ||
} | ||
} | ||
|
||
public void OnProvidersExecuted(ActionDescriptorProviderContext context) | ||
{ | ||
} | ||
|
||
private void AddActionDescriptors(IList<ActionDescriptor> actions, RazorProjectItem item, string template) | ||
{ | ||
var model = new PageModel(item.CombinedPath, item.PathWithoutExtension); | ||
var routePrefix = item.BasePath == "/" ? item.PathWithoutExtension : item.BasePath + item.PathWithoutExtension; | ||
model.Selectors.Add(CreateSelectorModel(routePrefix, template)); | ||
|
||
if (string.Equals(IndexFileName, item.Filename, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
model.Selectors.Add(CreateSelectorModel(item.BasePath, template)); | ||
} | ||
|
||
for (var i = 0; i < _pagesOptions.Conventions.Count; i++) | ||
{ | ||
_pagesOptions.Conventions[i].Apply(model); | ||
} | ||
|
||
var filters = new List<FilterDescriptor>(_mvcOptions.Filters.Count + model.Filters.Count); | ||
for (var i = 0; i < _mvcOptions.Filters.Count; i++) | ||
{ | ||
filters.Add(new FilterDescriptor(_mvcOptions.Filters[i], FilterScope.Global)); | ||
} | ||
|
||
for (var i = 0; i < model.Filters.Count; i++) | ||
{ | ||
filters.Add(new FilterDescriptor(model.Filters[i], FilterScope.Action)); | ||
} | ||
|
||
foreach (var selector in model.Selectors) | ||
{ | ||
actions.Add(new PageActionDescriptor() | ||
{ | ||
AttributeRouteInfo = new AttributeRouteInfo() | ||
{ | ||
Name = selector.AttributeRouteModel.Name, | ||
Order = selector.AttributeRouteModel.Order ?? 0, | ||
Template = selector.AttributeRouteModel.Template, | ||
}, | ||
DisplayName = $"Page: {item.Path}", | ||
FilterDescriptors = filters, | ||
Properties = new Dictionary<object, object>(model.Properties), | ||
RelativePath = item.CombinedPath, | ||
RouteValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) | ||
{ | ||
{ "page", item.PathWithoutExtension }, | ||
}, | ||
ViewEnginePath = item.Path, | ||
}); | ||
} | ||
} | ||
|
||
private static SelectorModel CreateSelectorModel(string prefix, string template) | ||
{ | ||
return new SelectorModel | ||
{ | ||
AttributeRouteModel = new AttributeRouteModel | ||
{ | ||
Template = AttributeRouteModel.CombineTemplates(prefix, template), | ||
} | ||
}; | ||
} | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageDirectiveFeature.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,33 @@ | ||
// 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.IO; | ||
using Microsoft.AspNetCore.Razor.Evolution; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure | ||
{ | ||
public static class PageDirectiveFeature | ||
{ | ||
public static bool TryGetRouteTemplate(RazorProjectItem projectItem, out string template) | ||
{ | ||
const string PageDirective = "@page"; | ||
|
||
string content; | ||
using (var streamReader = new StreamReader(projectItem.Read())) | ||
{ | ||
content = streamReader.ReadToEnd(); | ||
} | ||
|
||
if (content.StartsWith(PageDirective, StringComparison.Ordinal)) | ||
{ | ||
var newLineIndex = content.IndexOf(Environment.NewLine, PageDirective.Length); | ||
template = content.Substring(PageDirective.Length, newLineIndex - PageDirective.Length).Trim(); | ||
return true; | ||
} | ||
|
||
template = null; | ||
return false; | ||
} | ||
} | ||
} |
Oops, something went wrong.