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
911 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); | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
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,59 @@ | ||
// 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 | ||
{ | ||
public class PageModel | ||
{ | ||
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>(); | ||
} | ||
|
||
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))); | ||
} | ||
|
||
public string RelativePath { get; } | ||
|
||
public string ViewEnginePath { get; } | ||
|
||
public IList<IFilterMetadata> Filters { get; } | ||
|
||
public IDictionary<object, object> Properties { get; } | ||
|
||
public IList<SelectorModel> Selectors { get; } | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultRazorProject.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,59 @@ | ||
// 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.IO; | ||
using Microsoft.AspNetCore.Razor.Evolution; | ||
using Microsoft.Extensions.FileProviders; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure | ||
{ | ||
public class DefaultRazorProject : RazorProject | ||
{ | ||
private const string RazorFileExtension = ".cshtml"; | ||
private readonly IFileProvider _provider; | ||
|
||
public DefaultRazorProject(IFileProvider provider) | ||
{ | ||
_provider = provider; | ||
} | ||
|
||
public override IEnumerable<RazorProjectItem> EnumerateItems(string path) | ||
{ | ||
if (path == null) | ||
{ | ||
throw new ArgumentNullException(nameof(path)); | ||
} | ||
|
||
if (path.Length == 0 || path[0] != '/') | ||
{ | ||
throw new ArgumentException(Resources.RazorProject_PathMustStartWithForwardSlash); | ||
} | ||
|
||
return EnumerateFiles(_provider.GetDirectoryContents(path), path, ""); | ||
} | ||
|
||
private IEnumerable<RazorProjectItem> EnumerateFiles(IDirectoryContents directory, string basePath, string prefix) | ||
{ | ||
if (directory.Exists) | ||
{ | ||
foreach (var file in directory) | ||
{ | ||
if (file.IsDirectory) | ||
{ | ||
var children = EnumerateFiles(_provider.GetDirectoryContents(file.PhysicalPath), basePath, prefix + "/" + file.Name); | ||
foreach (var child in children) | ||
{ | ||
yield return child; | ||
} | ||
} | ||
else if (string.Equals(RazorFileExtension, Path.GetExtension(file.Name), StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
yield return new DefaultRazorProjectItem(file, basePath, prefix + "/" + file.Name); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/DefaultRazorProjectItem.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,32 @@ | ||
// 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.IO; | ||
using Microsoft.AspNetCore.Razor.Evolution; | ||
using Microsoft.Extensions.FileProviders; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure | ||
{ | ||
public class DefaultRazorProjectItem : RazorProjectItem | ||
{ | ||
private readonly IFileInfo _fileInfo; | ||
|
||
public DefaultRazorProjectItem(IFileInfo fileInfo, string basePath, string path) | ||
{ | ||
_fileInfo = fileInfo; | ||
BasePath = basePath; | ||
Path = path; | ||
} | ||
|
||
public override string BasePath { get; } | ||
|
||
public override string Path { get; } | ||
|
||
public override string PhysicalPath => _fileInfo.PhysicalPath; | ||
|
||
public override Stream Read() | ||
{ | ||
return _fileInfo.CreateReadStream(); | ||
} | ||
} | ||
} |
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), | ||
} | ||
}; | ||
} | ||
} | ||
} |
Oops, something went wrong.