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

Commit

Permalink
Add support for naming a page
Browse files Browse the repository at this point in the history
Fixes #5921
  • Loading branch information
pranavkm committed Apr 19, 2017
1 parent d65e77e commit 2c7e79c
Show file tree
Hide file tree
Showing 29 changed files with 892 additions and 177 deletions.
Expand Up @@ -68,6 +68,11 @@ public PageApplicationModel(PageApplicationModel other)
/// </summary>
public string ViewEnginePath { get; }

/// <summary>
/// Gets or sets the logical name for the page.
/// </summary>
public string Name { get; set; }

/// <summary>
/// Gets the applicable <see cref="IFilterMetadata"/> instances.
/// </summary>
Expand Down
Expand Up @@ -14,10 +14,20 @@ public CompiledPageInfo(string path, Type compiledType, string routePrefix)
RoutePrefix = routePrefix;
}

public CompiledPageInfo(string path, Type compiledType, string routePrefix, string name)
{
Path = path;
CompiledType = compiledType;
RoutePrefix = routePrefix;
Name = name;
}

public string Path { get; }

public string RoutePrefix { get; }

public string Name { get; }

public Type CompiledType { get; }
}
}
Expand Up @@ -170,6 +170,27 @@ public static RazorPagesOptions AuthorizeFolder(this RazorPagesOptions options,
public static RazorPagesOptions AuthorizeFolder(this RazorPagesOptions options, string folderPath) =>
AuthorizeFolder(options, folderPath, policy: string.Empty);

public static RazorPagesOptions SetPageName(this RazorPagesOptions options, string path, string name)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}

if (string.IsNullOrEmpty(path))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(path));
}

if (string.IsNullOrEmpty(name))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(name));
}

options.Conventions.Add(new PageConvention(path, model => model.Name = name));
return options;
}

private class PageConvention : IPageApplicationModelConvention
{
private readonly string _path;
Expand Down
Expand Up @@ -81,25 +81,45 @@ private void AddActionDescriptors(IList<ActionDescriptor> actions, PageApplicati

foreach (var selector in model.Selectors)
{
actions.Add(new PageActionDescriptor()
var order = selector.AttributeRouteModel.Order ?? 0;
var attributeRouteInfo = new AttributeRouteInfo()
{
AttributeRouteInfo = new AttributeRouteInfo()
{
Name = selector.AttributeRouteModel.Name,
Order = selector.AttributeRouteModel.Order ?? 0,
Template = selector.AttributeRouteModel.Template,
},
DisplayName = $"Page: {model.ViewEnginePath}",
FilterDescriptors = filters,
Properties = new Dictionary<object, object>(model.Properties),
RelativePath = model.RelativePath,
RouteValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "page", model.ViewEnginePath},
},
ViewEnginePath = model.ViewEnginePath,
});
Name = selector.AttributeRouteModel.Name,
Order = order,
Template = selector.AttributeRouteModel.Template,
};
actions.Add(CreateDescriptor(model, filters, attributeRouteInfo, model.ViewEnginePath));

if (!string.IsNullOrEmpty(model.Name) &&
!string.Equals(model.Name, model.ViewEnginePath, StringComparison.Ordinal))
{
var descriptor = CreateDescriptor(model, filters, attributeRouteInfo, model.Name);
// Register the alias as an action descriptor that ony participates in link generation.
descriptor.AttributeRouteInfo.SuppressPathMatching = true;
actions.Add(descriptor);
}
}
}

private static PageActionDescriptor CreateDescriptor(
PageApplicationModel model,
List<FilterDescriptor> filters,
AttributeRouteInfo attributeRouteInfo,
string pageValue)
{
return new PageActionDescriptor()
{
AttributeRouteInfo = attributeRouteInfo,
DisplayName = $"Page: {model.RelativePath}",
FilterDescriptors = filters,
Properties = new Dictionary<object, object>(model.Properties),
RelativePath = model.RelativePath,
RouteValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "page", pageValue },
},
ViewEnginePath = model.ViewEnginePath,
};
}
}
}
Expand Up @@ -3,61 +3,11 @@

using System;
using System.IO;
using Microsoft.AspNetCore.Razor.Language;

namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
public static class PageDirectiveFeature
{
public static bool TryGetPageDirective(RazorProjectItem projectItem, out string template)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}

return TryGetPageDirective(projectItem.Read, out template);
}

public static bool TryGetPageDirective(Func<Stream> streamFactory, out string template)
{
if (streamFactory == null)
{
throw new ArgumentNullException(nameof(streamFactory));
}

const string PageDirective = "@page";

string content;
using (var streamReader = new StreamReader(streamFactory()))
{
do
{
content = streamReader.ReadLine();

} while (content != null && string.IsNullOrWhiteSpace(content));
content = content?.Trim();
}

if (content == null || !content.StartsWith(PageDirective, StringComparison.Ordinal))
{
template = null;
return false;
}

template = content.Substring(PageDirective.Length, content.Length - PageDirective.Length).TrimStart();

if (template.StartsWith("\"") && template.EndsWith("\""))
{
template = template.Substring(1, template.Length - 2);
}
// If it's not in quotes it's not our template
else
{
template = string.Empty;
}

return true;
}

}
}
Expand Up @@ -65,7 +65,10 @@ private void EnsureCache()
}

var viewEnginePath = GetViewEnginePath(rootDirectory, page.Path);
var model = new PageApplicationModel(page.Path, viewEnginePath);
var model = new PageApplicationModel(page.Path, viewEnginePath)
{
Name = page.Name,
};
PageSelectorModel.PopulateDefaults(model, page.RoutePrefix);

cachedApplicationModels.Add(model);
Expand Down
@@ -0,0 +1,109 @@
// 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.Language;

namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
public struct PageDirectiveFeature
{
private const string DirectiveToken = "@page";
private static readonly char[] Separators = new[] { ' ' };

private PageDirectiveFeature(string routeTemplate, string name)
{
RouteTemplate = routeTemplate;
Name = name;
}

public string RouteTemplate { get; }

public string Name { get; }

public static bool TryGetPageDirective(
RazorProjectItem projectItem,
out PageDirectiveFeature directive)
{
if (projectItem == null)
{
throw new ArgumentNullException(nameof(projectItem));
}

return TryGetPageDirective(projectItem.Read, out directive);
}

public static bool TryGetPageDirective(
Func<Stream> streamFactory,
out PageDirectiveFeature directive)
{
if (streamFactory == null)
{
throw new ArgumentNullException(nameof(streamFactory));
}

var stream = streamFactory();
string content;
using (var streamReader = new StreamReader(stream))
{
do
{
content = streamReader.ReadLine();
} while (content != null && string.IsNullOrWhiteSpace(content));
}

directive = default(PageDirectiveFeature);
if (content == null)
{
return false;
}

var tokens = content.Split(Separators, 4, StringSplitOptions.RemoveEmptyEntries);
if (tokens.Length == 0 || tokens.Length > 3)
{
return false;
}

if (!string.Equals(tokens[0], DirectiveToken, StringComparison.Ordinal))
{
return false;
}

string template = null;
string pageName = null;
if (tokens.Length > 1)
{
template = tokens[1];
if (!TryGetUnquotedValue(ref template))
{
return false;
}
}

if (tokens.Length > 2)
{
pageName = tokens[2];
if (!TryGetUnquotedValue(ref pageName))
{
return false;
}
}

directive = new PageDirectiveFeature(template, pageName);
return true;
}

private static bool TryGetUnquotedValue(ref string value)
{
if (!value.StartsWith("\"", StringComparison.Ordinal) ||
!value.EndsWith("\"", StringComparison.Ordinal))
{
return false;
}

value = value.Substring(1, value.Length - 2);
return true;
}
}
}
Expand Up @@ -37,7 +37,7 @@ public void OnProvidersExecuting(PageApplicationModelProviderContext context)
continue;
}

if (!PageDirectiveFeature.TryGetPageDirective(item, out var routeTemplate))
if (!PageDirectiveFeature.TryGetPageDirective(item, out var directive))
{
// .cshtml pages without @page are not RazorPages.
continue;
Expand All @@ -46,7 +46,10 @@ public void OnProvidersExecuting(PageApplicationModelProviderContext context)
var pageApplicationModel = new PageApplicationModel(
relativePath: item.CombinedPath,
viewEnginePath: item.PathWithoutExtension);
PageSelectorModel.PopulateDefaults(pageApplicationModel, routeTemplate);

pageApplicationModel.Name = directive.Name;

PageSelectorModel.PopulateDefaults(pageApplicationModel, directive.RouteTemplate);

context.Results.Add(pageApplicationModel);
}
Expand Down

0 comments on commit 2c7e79c

Please sign in to comment.