-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add support for specifying filters on page models. #6417
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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="PageRouteModel"/>. | ||
/// </summary> | ||
public interface IPageRouteModelConvention | ||
{ | ||
/// <summary> | ||
/// Called to apply the convention to the <see cref="PageRouteModel"/>. | ||
/// </summary> | ||
/// <param name="model">The <see cref="PageRouteModel"/>.</param> | ||
void Apply(PageRouteModel model); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// 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> | ||
/// Builds or modifies an <see cref="PageRouteModelProviderContext"/> for Razor Page routing. | ||
/// </summary> | ||
public interface IPageRouteModelProvider | ||
{ | ||
/// <summary> | ||
/// Gets the order value for determining the order of execution of providers. Providers execute in | ||
/// ascending numeric value of the <see cref="Order"/> property. | ||
/// </summary> | ||
/// <remarks> | ||
/// <para> | ||
/// Providers are executed in an ordering determined by an ascending sort of the <see cref="Order"/> property. | ||
/// A provider with a lower numeric value of <see cref="Order"/> will have its | ||
/// <see cref="OnProvidersExecuting"/> called before that of a provider with a higher numeric value of | ||
/// <see cref="Order"/>. The <see cref="OnProvidersExecuted"/> method is called in the reverse ordering after | ||
/// all calls to <see cref="OnProvidersExecuting"/>. A provider with a lower numeric value of | ||
/// <see cref="Order"/> will have its <see cref="OnProvidersExecuted"/> method called after that of a provider | ||
/// with a higher numeric value of <see cref="Order"/>. | ||
/// </para> | ||
/// <para> | ||
/// If two providers have the same numeric value of <see cref="Order"/>, then their relative execution order | ||
/// is undefined. | ||
/// </para> | ||
/// </remarks> | ||
int Order { get; } | ||
|
||
/// <summary> | ||
/// Executed for the first pass of building <see cref="PageRouteModel"/> instances. See <see cref="Order"/>. | ||
/// </summary> | ||
/// <param name="context">The <see cref="PageRouteModelProviderContext"/>.</param> | ||
void OnProvidersExecuting(PageRouteModelProviderContext context); | ||
|
||
/// <summary> | ||
/// Executed for the second pass of building <see cref="PageRouteModel"/> instances. See <see cref="Order"/>. | ||
/// </summary> | ||
/// <param name="context">The <see cref="PageRouteModelProviderContext"/>.</param> | ||
void OnProvidersExecuted(PageRouteModelProviderContext context); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,10 @@ | |
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.AspNetCore.Mvc.RazorPages; | ||
using Microsoft.Extensions.Internal; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels | ||
{ | ||
|
@@ -16,26 +19,21 @@ public class PageApplicationModel | |
/// <summary> | ||
/// Initializes a new instance of <see cref="PageApplicationModel"/>. | ||
/// </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 PageApplicationModel(string relativePath, string viewEnginePath) | ||
public PageApplicationModel( | ||
PageActionDescriptor actionDescriptor, | ||
TypeInfo handlerType, | ||
IReadOnlyList<object> handlerAttributes) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should expose the route information here in a read-only format There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does that look like - something that looks like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah or maybe just the route template as a string. It's mostly for informational purposes. |
||
{ | ||
if (relativePath == null) | ||
{ | ||
throw new ArgumentNullException(nameof(relativePath)); | ||
} | ||
|
||
if (viewEnginePath == null) | ||
{ | ||
throw new ArgumentNullException(nameof(viewEnginePath)); | ||
} | ||
|
||
RelativePath = relativePath; | ||
ViewEnginePath = viewEnginePath; | ||
ActionDescriptor = actionDescriptor ?? throw new ArgumentNullException(nameof(actionDescriptor)); | ||
HandlerType = handlerType; | ||
|
||
Filters = new List<IFilterMetadata>(); | ||
Properties = new Dictionary<object, object>(); | ||
Selectors = new List<SelectorModel>(); | ||
Properties = new CopyOnWriteDictionary<object, object>( | ||
actionDescriptor.Properties, | ||
EqualityComparer<object>.Default); | ||
HandlerMethods = new List<PageHandlerModel>(); | ||
HandlerProperties = new List<PagePropertyModel>(); | ||
HandlerTypeAttributes = handlerAttributes; | ||
} | ||
|
||
/// <summary> | ||
|
@@ -49,24 +47,38 @@ public PageApplicationModel(PageApplicationModel other) | |
throw new ArgumentNullException(nameof(other)); | ||
} | ||
|
||
RelativePath = other.RelativePath; | ||
ViewEnginePath = other.ViewEnginePath; | ||
ActionDescriptor = other.ActionDescriptor; | ||
HandlerType = other.HandlerType; | ||
PageType = other.PageType; | ||
ModelType = other.ModelType; | ||
|
||
Filters = new List<IFilterMetadata>(other.Filters); | ||
Properties = new Dictionary<object, object>(other.Properties); | ||
|
||
Selectors = new List<SelectorModel>(other.Selectors.Select(m => new SelectorModel(m))); | ||
HandlerMethods = new List<PageHandlerModel>(other.HandlerMethods.Select(m => new PageHandlerModel(m))); | ||
HandlerProperties = new List<PagePropertyModel>(other.HandlerProperties.Select(p => new PagePropertyModel(p))); | ||
HandlerTypeAttributes = other.HandlerTypeAttributes; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the <see cref="PageActionDescriptor"/>. | ||
/// </summary> | ||
public PageActionDescriptor ActionDescriptor { get; } | ||
|
||
/// <summary> | ||
/// Gets the application root relative path for the page. | ||
/// </summary> | ||
public string RelativePath { get; } | ||
public string RelativePath => ActionDescriptor.RelativePath; | ||
|
||
/// <summary> | ||
/// Gets the path relative to the base path for page discovery. | ||
/// </summary> | ||
public string ViewEnginePath { get; } | ||
public string ViewEnginePath => ActionDescriptor.ViewEnginePath; | ||
|
||
/// <summary> | ||
/// Gets the route template for the page. | ||
/// </summary> | ||
public string RouteTemplate => ActionDescriptor.AttributeRouteInfo?.Template; | ||
|
||
/// <summary> | ||
/// Gets the applicable <see cref="IFilterMetadata"/> instances. | ||
|
@@ -79,8 +91,33 @@ public PageApplicationModel(PageApplicationModel other) | |
public IDictionary<object, object> Properties { get; } | ||
|
||
/// <summary> | ||
/// Gets the <see cref="SelectorModel"/> instances. | ||
/// Gets or sets the <see cref="TypeInfo"/> of the Razor page. | ||
/// </summary> | ||
public TypeInfo PageType { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the <see cref="TypeInfo"/> of the Razor page model. | ||
/// </summary> | ||
public TypeInfo ModelType { get; set; } | ||
|
||
/// <summary> | ||
/// Gets the <see cref="TypeInfo"/> of the handler. | ||
/// </summary> | ||
public TypeInfo HandlerType { get; } | ||
|
||
/// <summary> | ||
/// Gets the sequence of attributes declared on <see cref="HandlerType"/>. | ||
/// </summary> | ||
public IReadOnlyList<object> HandlerTypeAttributes { get; } | ||
|
||
/// <summary> | ||
/// Gets the sequence of <see cref="PageHandlerModel"/> instances. | ||
/// </summary> | ||
public IList<PageHandlerModel> HandlerMethods { get; } | ||
|
||
/// <summary> | ||
/// Gets the sequence of <see cref="PagePropertyModel"/> instances on <see cref="PageHandlerModel"/>. | ||
/// </summary> | ||
public IList<SelectorModel> Selectors { get; } | ||
public IList<PagePropertyModel> HandlerProperties { get; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ControllerModel has There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok 👍 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
// 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 System.Reflection; | ||
using Microsoft.AspNetCore.Mvc.RazorPages; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels | ||
{ | ||
|
@@ -10,9 +11,25 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels | |
/// </summary> | ||
public class PageApplicationModelProviderContext | ||
{ | ||
public PageApplicationModelProviderContext(PageActionDescriptor descriptor, TypeInfo pageTypeInfo) | ||
{ | ||
ActionDescriptor = descriptor; | ||
PageType = pageTypeInfo; | ||
} | ||
|
||
/// <summary> | ||
/// Gets the <see cref="PageActionDescriptor"/>. | ||
/// </summary> | ||
public PageActionDescriptor ActionDescriptor { get; } | ||
|
||
/// <summary> | ||
/// Gets the page <see cref="TypeInfo"/>. | ||
/// </summary> | ||
public TypeInfo PageType { get; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this here? Isn't this redundant with the AD? The type isn't super useful on it's own because it's always generated, I'd say just the AD should be here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah ok, I guess we do need it. 👍 |
||
|
||
/// <summary> | ||
/// Gets the <see cref="PageApplicationModel"/> instances. | ||
/// Gets or sets the <see cref="ApplicationModels.PageApplicationModel"/>. | ||
/// </summary> | ||
public IList<PageApplicationModel> Results { get; } = new List<PageApplicationModel>(); | ||
public PageApplicationModel PageApplicationModel { get; set; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// 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.Diagnostics; | ||
using System.Linq; | ||
using System.Reflection; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels | ||
{ | ||
/// <summary> | ||
/// Represents a handler in a <see cref="PageApplicationModel"/>. | ||
/// </summary> | ||
[DebuggerDisplay("PageHandlerModel: Name={" + nameof(PageHandlerModel.Name) + "}")] | ||
public class PageHandlerModel : ICommonModel | ||
{ | ||
/// <summary> | ||
/// Creates a new <see cref="PageHandlerModel"/>. | ||
/// </summary> | ||
/// <param name="handlerMethod">The <see cref="System.Reflection.MethodInfo"/> for the handler.</param> | ||
/// <param name="attributes">Any attributes annotated on the handler method.</param> | ||
public PageHandlerModel( | ||
MethodInfo handlerMethod, | ||
IReadOnlyList<object> attributes) | ||
{ | ||
MethodInfo = handlerMethod ?? throw new ArgumentNullException(nameof(handlerMethod)); | ||
Attributes = attributes ?? throw new ArgumentNullException(nameof(attributes)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😢 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't worry, one of these days all our null checks are going to look like this 😈 |
||
|
||
Parameters = new List<PageParameterModel>(); | ||
Properties = new Dictionary<object, object>(); | ||
} | ||
|
||
/// <summary> | ||
/// Creats a new instance of <see cref="PageHandlerModel"/> from a given <see cref="PageHandlerModel"/>. | ||
/// </summary> | ||
/// <param name="other">The <see cref="PageHandlerModel"/> which needs to be copied.</param> | ||
public PageHandlerModel(PageHandlerModel other) | ||
{ | ||
if (other == null) | ||
{ | ||
throw new ArgumentNullException(nameof(other)); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either you're with us or you're against us. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, that's the annoying bit - it only works for assignments, not regular null checks. Super inconsistent. Sort of one of the reasons I wasn't a big fan of it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep. This is the |
||
|
||
MethodInfo = other.MethodInfo; | ||
HandlerName = other.HandlerName; | ||
HttpMethod = other.HttpMethod; | ||
Name = other.Name; | ||
|
||
Page = other.Page; | ||
|
||
// These are just metadata, safe to create new collections | ||
Attributes = new List<object>(other.Attributes); | ||
Properties = new Dictionary<object, object>(other.Properties); | ||
|
||
// Make a deep copy of other 'model' types. | ||
Parameters = new List<PageParameterModel>(other.Parameters.Select(p => new PageParameterModel(p) { Handler = this })); | ||
} | ||
|
||
/// <summary> | ||
/// Gets the <see cref="System.Reflection.MethodInfo"/> for the handler. | ||
/// </summary> | ||
public MethodInfo MethodInfo { get; } | ||
|
||
/// <summary> | ||
/// Gets or sets the HTTP method supported by this handler. | ||
/// </summary> | ||
public string HttpMethod { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the handler method name. | ||
/// </summary> | ||
public string HandlerName { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets a descriptive name for the handler. | ||
/// </summary> | ||
public string Name { get; set; } | ||
|
||
/// <summary> | ||
/// Gets the seqeunce of <see cref="PageParameterModel"/> instances. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sequence |
||
/// </summary> | ||
public IList<PageParameterModel> Parameters { get; } | ||
|
||
/// <summary> | ||
/// Gets or sets the <see cref="PageApplicationModel"/>. | ||
/// </summary> | ||
public PageApplicationModel Page { get; set; } | ||
|
||
/// <inheritdoc /> | ||
public IReadOnlyList<object> Attributes { get; } | ||
|
||
/// <inheritdoc /> | ||
public IDictionary<object, object> Properties { get; } | ||
|
||
MemberInfo ICommonModel.MemberInfo => MethodInfo; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// 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.Diagnostics; | ||
using System.Reflection; | ||
using Microsoft.AspNetCore.Mvc.ModelBinding; | ||
|
||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels | ||
{ | ||
[DebuggerDisplay("PageParameterModel: Name={ParameterName}")] | ||
public class PageParameterModel : ICommonModel, IBindingModel | ||
{ | ||
public PageParameterModel( | ||
ParameterInfo parameterInfo, | ||
IReadOnlyList<object> attributes) | ||
{ | ||
ParameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo)); | ||
|
||
if (attributes == null) | ||
{ | ||
throw new ArgumentNullException(nameof(attributes)); | ||
} | ||
|
||
Properties = new Dictionary<object, object>(); | ||
Attributes = new List<object>(attributes); | ||
} | ||
|
||
public PageParameterModel(PageParameterModel other) | ||
{ | ||
if (other == null) | ||
{ | ||
throw new ArgumentNullException(nameof(other)); | ||
} | ||
|
||
Handler = other.Handler; | ||
Attributes = new List<object>(other.Attributes); | ||
BindingInfo = other.BindingInfo == null ? null : new BindingInfo(other.BindingInfo); | ||
ParameterInfo = other.ParameterInfo; | ||
ParameterName = other.ParameterName; | ||
Properties = new Dictionary<object, object>(other.Properties); | ||
} | ||
|
||
public PageHandlerModel Handler { get; set; } | ||
|
||
public IReadOnlyList<object> Attributes { get; } | ||
|
||
public IDictionary<object, object> Properties { get; } | ||
|
||
MemberInfo ICommonModel.MemberInfo => ParameterInfo.Member; | ||
|
||
string ICommonModel.Name => ParameterName; | ||
|
||
public ParameterInfo ParameterInfo { get; } | ||
|
||
public string ParameterName { get; set; } | ||
|
||
public BindingInfo BindingInfo { get; set; } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love this name, but I don't have a better one in mind.