Add support for running conventions on controller properties, Razor Page parameter and properties
Fixes #6935
This commit is contained in:
parent
a08fae1a28
commit
dbff416be6
|
|
@ -0,0 +1,21 @@
|
||||||
|
// 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 properties and parameters on controllers and Razor Pages.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// To use this interface, create an <see cref="System.Attribute"/> class which implements the interface and
|
||||||
|
/// place it on an action method parameter.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IParameterModelBaseConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called to apply the convention to the <see cref="ParameterModelBase"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter">The <see cref="ParameterModelBase"/>.</param>
|
||||||
|
void Apply(ParameterModelBase parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allows customization of the <see cref="ControllerModel"/>.
|
/// Allows customization of the <see cref="ParameterModel"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// To use this interface, create an <see cref="System.Attribute"/> class which implements the interface and
|
/// To use this interface, create an <see cref="System.Attribute"/> class which implements the interface and
|
||||||
|
|
@ -15,10 +15,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public interface IParameterModelConvention
|
public interface IParameterModelConvention
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Called to apply the convention to the <see cref="ParameterModel"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parameter">The <see cref="ParameterModel"/>.</param>
|
|
||||||
void Apply(ParameterModel parameter);
|
void Apply(ParameterModel parameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,22 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("ParameterModel: Name={ParameterName}")]
|
[DebuggerDisplay("ParameterModel: Name={ParameterName}")]
|
||||||
public class ParameterModel : ICommonModel, IBindingModel
|
public class ParameterModel : ParameterModelBase, ICommonModel
|
||||||
{
|
{
|
||||||
public ParameterModel(
|
public ParameterModel(
|
||||||
ParameterInfo parameterInfo,
|
ParameterInfo parameterInfo,
|
||||||
IReadOnlyList<object> attributes)
|
IReadOnlyList<object> attributes)
|
||||||
|
: base(parameterInfo?.ParameterType, attributes)
|
||||||
{
|
{
|
||||||
if (parameterInfo == null)
|
ParameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo));
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(parameterInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attributes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
ParameterInfo = parameterInfo;
|
|
||||||
Properties = new Dictionary<object, object>();
|
|
||||||
Attributes = new List<object>(attributes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParameterModel(ParameterModel other)
|
public ParameterModel(ParameterModel other)
|
||||||
|
: base(other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
{
|
{
|
||||||
|
|
@ -39,27 +28,23 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
}
|
}
|
||||||
|
|
||||||
Action = other.Action;
|
Action = other.Action;
|
||||||
Attributes = new List<object>(other.Attributes);
|
|
||||||
BindingInfo = other.BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
|
||||||
ParameterInfo = other.ParameterInfo;
|
ParameterInfo = other.ParameterInfo;
|
||||||
ParameterName = other.ParameterName;
|
|
||||||
Properties = new Dictionary<object, object>(other.Properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionModel Action { get; set; }
|
public ActionModel Action { get; set; }
|
||||||
|
|
||||||
public IReadOnlyList<object> Attributes { get; }
|
public new IDictionary<object, object> Properties => base.Properties;
|
||||||
|
|
||||||
public IDictionary<object, object> Properties { get; }
|
public new IReadOnlyList<object> Attributes => base.Attributes;
|
||||||
|
|
||||||
MemberInfo ICommonModel.MemberInfo => ParameterInfo.Member;
|
MemberInfo ICommonModel.MemberInfo => ParameterInfo.Member;
|
||||||
|
|
||||||
string ICommonModel.Name => ParameterName;
|
|
||||||
|
|
||||||
public ParameterInfo ParameterInfo { get; }
|
public ParameterInfo ParameterInfo { get; }
|
||||||
|
|
||||||
public string ParameterName { get; set; }
|
public string ParameterName
|
||||||
|
{
|
||||||
public BindingInfo BindingInfo { get; set; }
|
get => Name;
|
||||||
|
set => Name = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// 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.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A model type for reading and manipulation properties and parameters.
|
||||||
|
/// <para>
|
||||||
|
/// Derived instances of this type represent properties and parameters for controllers, and Razor Pages.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ParameterModelBase : IBindingModel
|
||||||
|
{
|
||||||
|
protected ParameterModelBase(
|
||||||
|
Type parameterType,
|
||||||
|
IReadOnlyList<object> attributes)
|
||||||
|
{
|
||||||
|
ParameterType = parameterType ?? throw new ArgumentNullException(nameof(parameterType));
|
||||||
|
Attributes = new List<object>(attributes ?? throw new ArgumentNullException(nameof(attributes)));
|
||||||
|
|
||||||
|
Properties = new Dictionary<object, object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ParameterModelBase(ParameterModelBase other)
|
||||||
|
{
|
||||||
|
if (other == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterType = other.ParameterType;
|
||||||
|
Attributes = new List<object>(other.Attributes);
|
||||||
|
BindingInfo = other.BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
||||||
|
Name = other.Name;
|
||||||
|
Properties = new Dictionary<object, object>(other.Properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<object> Attributes { get; }
|
||||||
|
|
||||||
|
public IDictionary<object, object> Properties { get; }
|
||||||
|
|
||||||
|
public Type ParameterType { get; }
|
||||||
|
|
||||||
|
public string Name { get; protected set; }
|
||||||
|
|
||||||
|
public BindingInfo BindingInfo { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// A type which is used to represent a property in a <see cref="ControllerModel"/>.
|
/// A type which is used to represent a property in a <see cref="ControllerModel"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay("PropertyModel: Name={PropertyName}")]
|
[DebuggerDisplay("PropertyModel: Name={PropertyName}")]
|
||||||
public class PropertyModel : ICommonModel, IBindingModel
|
public class PropertyModel : ParameterModelBase, ICommonModel, IBindingModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="PropertyModel"/>.
|
/// Creates a new instance of <see cref="PropertyModel"/>.
|
||||||
|
|
@ -23,20 +23,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
public PropertyModel(
|
public PropertyModel(
|
||||||
PropertyInfo propertyInfo,
|
PropertyInfo propertyInfo,
|
||||||
IReadOnlyList<object> attributes)
|
IReadOnlyList<object> attributes)
|
||||||
|
: base(propertyInfo?.PropertyType, attributes)
|
||||||
{
|
{
|
||||||
if (propertyInfo == null)
|
PropertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(propertyInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attributes == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(attributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyInfo = propertyInfo;
|
|
||||||
Properties = new Dictionary<object, object>();
|
|
||||||
Attributes = new List<object>(attributes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -44,6 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The <see cref="PropertyModel"/> which needs to be copied.</param>
|
/// <param name="other">The <see cref="PropertyModel"/> which needs to be copied.</param>
|
||||||
public PropertyModel(PropertyModel other)
|
public PropertyModel(PropertyModel other)
|
||||||
|
: base(other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
{
|
{
|
||||||
|
|
@ -51,11 +41,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller = other.Controller;
|
Controller = other.Controller;
|
||||||
Attributes = new List<object>(other.Attributes);
|
|
||||||
BindingInfo = BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
BindingInfo = BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
||||||
PropertyInfo = other.PropertyInfo;
|
PropertyInfo = other.PropertyInfo;
|
||||||
PropertyName = other.PropertyName;
|
|
||||||
Properties = new Dictionary<object, object>(other.Properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -63,30 +50,18 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ControllerModel Controller { get; set; }
|
public ControllerModel Controller { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets any attributes which are annotated on the property.
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyList<object> Attributes { get; }
|
|
||||||
|
|
||||||
public IDictionary<object, object> Properties { get; }
|
|
||||||
|
|
||||||
MemberInfo ICommonModel.MemberInfo => PropertyInfo;
|
MemberInfo ICommonModel.MemberInfo => PropertyInfo;
|
||||||
|
|
||||||
string ICommonModel.Name => PropertyName;
|
public new IDictionary<object, object> Properties => base.Properties;
|
||||||
|
|
||||||
/// <summary>
|
public new IReadOnlyList<object> Attributes => base.Attributes;
|
||||||
/// Gets or sets the <see cref="BindingInfo"/> associated with this model.
|
|
||||||
/// </summary>
|
|
||||||
public BindingInfo BindingInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying <see cref="PropertyInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
public PropertyInfo PropertyInfo { get; }
|
public PropertyInfo PropertyInfo { get; }
|
||||||
|
|
||||||
/// <summary>
|
public string PropertyName
|
||||||
/// Gets or sets the name of the property represented by this model.
|
{
|
||||||
/// </summary>
|
get => Name;
|
||||||
public string PropertyName { get; set; }
|
set => Name = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
@ -18,7 +18,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="list">The list of <see cref="IApplicationModelConvention"/>s.</param>
|
/// <param name="list">The list of <see cref="IApplicationModelConvention"/>s.</param>
|
||||||
/// <typeparam name="TApplicationModelConvention">The type to remove.</typeparam>
|
/// <typeparam name="TApplicationModelConvention">The type to remove.</typeparam>
|
||||||
public static void RemoveType<TApplicationModelConvention>(this IList<IApplicationModelConvention> list) where TApplicationModelConvention : IApplicationModelConvention
|
public static void RemoveType<TApplicationModelConvention>(this IList<IApplicationModelConvention> list)
|
||||||
|
where TApplicationModelConvention : IApplicationModelConvention
|
||||||
{
|
{
|
||||||
if (list == null)
|
if (list == null)
|
||||||
{
|
{
|
||||||
|
|
@ -127,17 +128,36 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
conventions.Add(new ParameterApplicationModelConvention(parameterModelConvention));
|
conventions.Add(new ParameterApplicationModelConvention(parameterModelConvention));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a <see cref="IParameterModelBaseConvention"/> to all properties and parameters in the application.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="conventions">The list of <see cref="IApplicationModelConvention"/>
|
||||||
|
/// in <see cref="AspNetCore.Mvc.MvcOptions"/>.</param>
|
||||||
|
/// <param name="parameterModelConvention">The <see cref="IParameterModelBaseConvention"/> which needs to be
|
||||||
|
/// added.</param>
|
||||||
|
public static void Add(
|
||||||
|
this IList<IApplicationModelConvention> conventions,
|
||||||
|
IParameterModelBaseConvention parameterModelConvention)
|
||||||
|
{
|
||||||
|
if (conventions == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(conventions));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameterModelConvention == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parameterModelConvention));
|
||||||
|
}
|
||||||
|
|
||||||
|
conventions.Add(new ParameterBaseApplicationModelConvention(parameterModelConvention));
|
||||||
|
}
|
||||||
|
|
||||||
private class ParameterApplicationModelConvention : IApplicationModelConvention
|
private class ParameterApplicationModelConvention : IApplicationModelConvention
|
||||||
{
|
{
|
||||||
private readonly IParameterModelConvention _parameterModelConvention;
|
private readonly IParameterModelConvention _parameterModelConvention;
|
||||||
|
|
||||||
public ParameterApplicationModelConvention(IParameterModelConvention parameterModelConvention)
|
public ParameterApplicationModelConvention(IParameterModelConvention parameterModelConvention)
|
||||||
{
|
{
|
||||||
if (parameterModelConvention == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(parameterModelConvention));
|
|
||||||
}
|
|
||||||
|
|
||||||
_parameterModelConvention = parameterModelConvention;
|
_parameterModelConvention = parameterModelConvention;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,6 +187,36 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ParameterBaseApplicationModelConvention :
|
||||||
|
IApplicationModelConvention, IParameterModelBaseConvention
|
||||||
|
{
|
||||||
|
private readonly IParameterModelBaseConvention _parameterBaseModelConvention;
|
||||||
|
|
||||||
|
public ParameterBaseApplicationModelConvention(IParameterModelBaseConvention parameterModelBaseConvention)
|
||||||
|
{
|
||||||
|
_parameterBaseModelConvention = parameterModelBaseConvention;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Apply(ApplicationModel application)
|
||||||
|
{
|
||||||
|
if (application == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(application));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IParameterModelBaseConvention.Apply(ParameterModelBase parameterModel)
|
||||||
|
{
|
||||||
|
if (parameterModel == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parameterModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
_parameterBaseModelConvention.Apply(parameterModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ActionApplicationModelConvention : IApplicationModelConvention
|
private class ActionApplicationModelConvention : IApplicationModelConvention
|
||||||
{
|
{
|
||||||
private readonly IActionModelConvention _actionModelConvention;
|
private readonly IActionModelConvention _actionModelConvention;
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
convention.Apply(applicationModel);
|
convention.Apply(applicationModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var controllers = applicationModel.Controllers.ToArray();
|
||||||
// First apply the conventions from attributes in decreasing order of scope.
|
// First apply the conventions from attributes in decreasing order of scope.
|
||||||
foreach (var controller in applicationModel.Controllers)
|
foreach (var controller in controllers)
|
||||||
{
|
{
|
||||||
// ToArray is needed here to prevent issues with modifying the attributes collection
|
// ToArray is needed here to prevent issues with modifying the attributes collection
|
||||||
// while iterating it.
|
// while iterating it.
|
||||||
|
|
@ -54,7 +55,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
controllerConvention.Apply(controller);
|
controllerConvention.Apply(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var action in controller.Actions)
|
var actions = controller.Actions.ToArray();
|
||||||
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
// ToArray is needed here to prevent issues with modifying the attributes collection
|
// ToArray is needed here to prevent issues with modifying the attributes collection
|
||||||
// while iterating it.
|
// while iterating it.
|
||||||
|
|
@ -68,7 +70,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
actionConvention.Apply(action);
|
actionConvention.Apply(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var parameter in action.Parameters)
|
var parameters = action.Parameters.ToArray();
|
||||||
|
foreach (var parameter in parameters)
|
||||||
{
|
{
|
||||||
// ToArray is needed here to prevent issues with modifying the attributes collection
|
// ToArray is needed here to prevent issues with modifying the attributes collection
|
||||||
// while iterating it.
|
// while iterating it.
|
||||||
|
|
@ -81,9 +84,35 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
parameterConvention.Apply(parameter);
|
parameterConvention.Apply(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var parameterBaseConventions = GetConventions<IParameterModelBaseConvention>(conventions, parameter.Attributes);
|
||||||
|
foreach (var parameterConvention in parameterBaseConventions)
|
||||||
|
{
|
||||||
|
parameterConvention.Apply(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = controller.ControllerProperties.ToArray();
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
var parameterBaseConventions = GetConventions<IParameterModelBaseConvention>(conventions, property.Attributes);
|
||||||
|
|
||||||
|
foreach (var parameterConvention in parameterBaseConventions)
|
||||||
|
{
|
||||||
|
parameterConvention.Apply(property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TConvention> GetConventions<TConvention>(
|
||||||
|
IEnumerable<IApplicationModelConvention> conventions,
|
||||||
|
IReadOnlyList<object> attributes)
|
||||||
|
{
|
||||||
|
return Enumerable.Concat(
|
||||||
|
conventions.OfType<TConvention>(),
|
||||||
|
attributes.OfType<TConvention>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 <see cref="PageHandlerModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
public interface IPageHandlerModelConvention : IPageConvention
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called to apply the convention to the <see cref="PageHandlerModel"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The <see cref="PageHandlerModel"/>.</param>
|
||||||
|
void Apply(PageHandlerModel model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,29 +5,32 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
[DebuggerDisplay("PageParameterModel: Name={ParameterName}")]
|
[DebuggerDisplay("PageParameterModel: Name={ParameterName}")]
|
||||||
public class PageParameterModel : ICommonModel, IBindingModel
|
public class PageParameterModel : ParameterModelBase, ICommonModel, IBindingModel
|
||||||
{
|
{
|
||||||
public PageParameterModel(
|
public PageParameterModel(
|
||||||
ParameterInfo parameterInfo,
|
ParameterInfo parameterInfo,
|
||||||
IReadOnlyList<object> attributes)
|
IReadOnlyList<object> attributes)
|
||||||
|
: base(parameterInfo?.ParameterType, attributes)
|
||||||
{
|
{
|
||||||
ParameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo));
|
if (parameterInfo == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(parameterInfo));
|
||||||
|
}
|
||||||
|
|
||||||
if (attributes == null)
|
if (attributes == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(attributes));
|
throw new ArgumentNullException(nameof(attributes));
|
||||||
}
|
}
|
||||||
|
|
||||||
Properties = new Dictionary<object, object>();
|
ParameterInfo = parameterInfo;
|
||||||
Attributes = new List<object>(attributes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageParameterModel(PageParameterModel other)
|
public PageParameterModel(PageParameterModel other)
|
||||||
|
: base(other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
{
|
{
|
||||||
|
|
@ -35,27 +38,19 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
}
|
}
|
||||||
|
|
||||||
Handler = other.Handler;
|
Handler = other.Handler;
|
||||||
Attributes = new List<object>(other.Attributes);
|
|
||||||
BindingInfo = other.BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
|
||||||
ParameterInfo = other.ParameterInfo;
|
ParameterInfo = other.ParameterInfo;
|
||||||
ParameterName = other.ParameterName;
|
|
||||||
Properties = new Dictionary<object, object>(other.Properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PageHandlerModel Handler { get; set; }
|
public PageHandlerModel Handler { get; set; }
|
||||||
|
|
||||||
public IReadOnlyList<object> Attributes { get; }
|
|
||||||
|
|
||||||
public IDictionary<object, object> Properties { get; }
|
|
||||||
|
|
||||||
MemberInfo ICommonModel.MemberInfo => ParameterInfo.Member;
|
MemberInfo ICommonModel.MemberInfo => ParameterInfo.Member;
|
||||||
|
|
||||||
string ICommonModel.Name => ParameterName;
|
|
||||||
|
|
||||||
public ParameterInfo ParameterInfo { get; }
|
public ParameterInfo ParameterInfo { get; }
|
||||||
|
|
||||||
public string ParameterName { get; set; }
|
public string ParameterName
|
||||||
|
{
|
||||||
public BindingInfo BindingInfo { get; set; }
|
get => Name;
|
||||||
|
set => Name = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// Represents a property in a <see cref="PageApplicationModel"/>.
|
/// Represents a property in a <see cref="PageApplicationModel"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay("PagePropertyModel: Name={PropertyName}")]
|
[DebuggerDisplay("PagePropertyModel: Name={PropertyName}")]
|
||||||
public class PagePropertyModel : ICommonModel, IBindingModel
|
public class PagePropertyModel : ParameterModelBase, ICommonModel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="PagePropertyModel"/>.
|
/// Creates a new instance of <see cref="PagePropertyModel"/>.
|
||||||
|
|
@ -23,10 +23,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
public PagePropertyModel(
|
public PagePropertyModel(
|
||||||
PropertyInfo propertyInfo,
|
PropertyInfo propertyInfo,
|
||||||
IReadOnlyList<object> attributes)
|
IReadOnlyList<object> attributes)
|
||||||
|
: base(propertyInfo?.PropertyType, attributes)
|
||||||
{
|
{
|
||||||
PropertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));
|
PropertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo));
|
||||||
Properties = new Dictionary<object, object>();
|
|
||||||
Attributes = new List<object>(attributes) ?? throw new ArgumentNullException(nameof(attributes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -34,6 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The <see cref="PagePropertyModel"/> which needs to be copied.</param>
|
/// <param name="other">The <see cref="PagePropertyModel"/> which needs to be copied.</param>
|
||||||
public PagePropertyModel(PagePropertyModel other)
|
public PagePropertyModel(PagePropertyModel other)
|
||||||
|
: base(other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
{
|
{
|
||||||
|
|
@ -41,11 +41,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
}
|
}
|
||||||
|
|
||||||
Page = other.Page;
|
Page = other.Page;
|
||||||
Attributes = new List<object>(other.Attributes);
|
|
||||||
BindingInfo = BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
BindingInfo = BindingInfo == null ? null : new BindingInfo(other.BindingInfo);
|
||||||
PropertyInfo = other.PropertyInfo;
|
PropertyInfo = other.PropertyInfo;
|
||||||
PropertyName = other.PropertyName;
|
|
||||||
Properties = new Dictionary<object, object>(other.Properties);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -53,31 +50,14 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PageApplicationModel Page { get; set; }
|
public PageApplicationModel Page { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets any attributes which are annotated on the property.
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyList<object> Attributes { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IDictionary<object, object> Properties { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <see cref="BindingInfo"/> associated with this model.
|
|
||||||
/// </summary>
|
|
||||||
public BindingInfo BindingInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the underlying <see cref="PropertyInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
public PropertyInfo PropertyInfo { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name of the property represented by this model.
|
|
||||||
/// </summary>
|
|
||||||
public string PropertyName { get; set; }
|
|
||||||
|
|
||||||
MemberInfo ICommonModel.MemberInfo => PropertyInfo;
|
MemberInfo ICommonModel.MemberInfo => PropertyInfo;
|
||||||
|
|
||||||
string ICommonModel.Name => PropertyName;
|
public PropertyInfo PropertyInfo { get; }
|
||||||
|
|
||||||
|
public string PropertyName
|
||||||
|
{
|
||||||
|
get => Name;
|
||||||
|
set => Name = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -143,6 +143,30 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
return conventions;
|
return conventions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified <paramref name="convention"/> to <paramref name="conventions"/>.
|
||||||
|
/// The added convention will apply to all handler properties and parameters on handler methods.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="conventions">The <see cref="PageConventionCollection"/> to configure.</param>
|
||||||
|
/// <param name="convention">The <see cref="IParameterModelBaseConvention"/> to apply.</param>
|
||||||
|
/// <returns>The <see cref="PageConventionCollection"/>.</returns>
|
||||||
|
public static PageConventionCollection Add(this PageConventionCollection conventions, IParameterModelBaseConvention convention)
|
||||||
|
{
|
||||||
|
if (conventions == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(conventions));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (convention == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(convention));
|
||||||
|
}
|
||||||
|
|
||||||
|
var adapter = new ParameterModelBaseConventionAdapter(convention);
|
||||||
|
conventions.Add(adapter);
|
||||||
|
return conventions;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a <see cref="AllowAnonymousFilter"/> to all pages under the specified area folder.
|
/// Adds a <see cref="AllowAnonymousFilter"/> to all pages under the specified area folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -461,5 +485,20 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ParameterModelBaseConventionAdapter : IPageConvention, IParameterModelBaseConvention
|
||||||
|
{
|
||||||
|
private readonly IParameterModelBaseConvention _convention;
|
||||||
|
|
||||||
|
public ParameterModelBaseConventionAdapter(IParameterModelBaseConvention convention)
|
||||||
|
{
|
||||||
|
_convention = convention;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Apply(ParameterModelBase parameter)
|
||||||
|
{
|
||||||
|
_convention.Apply(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
{
|
{
|
||||||
private readonly IPageApplicationModelProvider[] _applicationModelProviders;
|
private readonly IPageApplicationModelProvider[] _applicationModelProviders;
|
||||||
private readonly IViewCompilerProvider _viewCompilerProvider;
|
private readonly IViewCompilerProvider _viewCompilerProvider;
|
||||||
private readonly IPageApplicationModelConvention[] _conventions;
|
private readonly PageConventionCollection _conventions;
|
||||||
private readonly FilterCollection _globalFilters;
|
private readonly FilterCollection _globalFilters;
|
||||||
|
|
||||||
public DefaultPageLoader(
|
public DefaultPageLoader(
|
||||||
|
|
@ -30,9 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
.OrderBy(p => p.Order)
|
.OrderBy(p => p.Order)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
_viewCompilerProvider = viewCompilerProvider;
|
_viewCompilerProvider = viewCompilerProvider;
|
||||||
_conventions = pageOptions.Value.Conventions
|
_conventions = pageOptions.Value.Conventions;
|
||||||
.OfType<IPageApplicationModelConvention>()
|
|
||||||
.ToArray();
|
|
||||||
_globalFilters = mvcOptions.Value.Filters;
|
_globalFilters = mvcOptions.Value.Filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,12 +58,58 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
_applicationModelProviders[i].OnProvidersExecuted(context);
|
_applicationModelProviders[i].OnProvidersExecuted(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < _conventions.Length; i++)
|
ApplyConventions(_conventions, context.PageApplicationModel);
|
||||||
{
|
|
||||||
_conventions[i].Apply(context.PageApplicationModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CompiledPageActionDescriptorBuilder.Build(context.PageApplicationModel, _globalFilters);
|
return CompiledPageActionDescriptorBuilder.Build(context.PageApplicationModel, _globalFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void ApplyConventions(
|
||||||
|
PageConventionCollection conventions,
|
||||||
|
PageApplicationModel pageApplicationModel)
|
||||||
|
{
|
||||||
|
var applicationModelConventions = GetConventions<IPageApplicationModelConvention>(pageApplicationModel.HandlerTypeAttributes);
|
||||||
|
foreach (var convention in applicationModelConventions)
|
||||||
|
{
|
||||||
|
convention.Apply(pageApplicationModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
var handlers = pageApplicationModel.HandlerMethods.ToArray();
|
||||||
|
foreach (var handlerModel in handlers)
|
||||||
|
{
|
||||||
|
var handlerModelConventions = GetConventions<IPageHandlerModelConvention>(handlerModel.Attributes);
|
||||||
|
foreach (var convention in handlerModelConventions)
|
||||||
|
{
|
||||||
|
convention.Apply(handlerModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameterModels = handlerModel.Parameters.ToArray();
|
||||||
|
foreach (var parameterModel in parameterModels)
|
||||||
|
{
|
||||||
|
var parameterModelConventions = GetConventions<IParameterModelBaseConvention>(parameterModel.Attributes);
|
||||||
|
foreach (var convention in parameterModelConventions)
|
||||||
|
{
|
||||||
|
convention.Apply(parameterModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = pageApplicationModel.HandlerProperties.ToArray();
|
||||||
|
foreach (var propertyModel in properties)
|
||||||
|
{
|
||||||
|
var propertyModelConventions = GetConventions<IParameterModelBaseConvention>(propertyModel.Attributes);
|
||||||
|
foreach (var convention in propertyModelConventions)
|
||||||
|
{
|
||||||
|
convention.Apply(propertyModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<TConvention> GetConventions<TConvention>(
|
||||||
|
IReadOnlyList<object> attributes)
|
||||||
|
{
|
||||||
|
return Enumerable.Concat(
|
||||||
|
conventions.OfType<TConvention>(),
|
||||||
|
attributes.OfType<TConvention>());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,8 +18,16 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var app = new ApplicationModel();
|
var app = new ApplicationModel();
|
||||||
app.Controllers.Add(new ControllerModel(typeof(HelloController).GetTypeInfo(), new List<object>()));
|
var controllerType = typeof(HelloController);
|
||||||
app.Controllers.Add(new ControllerModel(typeof(WorldController).GetTypeInfo(), new List<object>()));
|
var controllerModel = new ControllerModel(controllerType.GetTypeInfo(), Array.Empty<object>());
|
||||||
|
app.Controllers.Add(controllerModel);
|
||||||
|
|
||||||
|
var actionModel = new ActionModel(controllerType.GetMethod(nameof(HelloController.GetInfo)), Array.Empty<object>());
|
||||||
|
controllerModel.Actions.Add(actionModel);
|
||||||
|
var parameterModel = new ParameterModel(
|
||||||
|
controllerType.GetMethod(nameof(HelloController.GetInfo)).GetParameters()[0],
|
||||||
|
Array.Empty<object>());
|
||||||
|
actionModel.Parameters.Add(parameterModel);
|
||||||
|
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
options.Conventions.Add(new SimpleParameterConvention());
|
options.Conventions.Add(new SimpleParameterConvention());
|
||||||
|
|
@ -28,18 +36,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
options.Conventions[0].Apply(app);
|
options.Conventions[0].Apply(app);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
foreach (var controller in app.Controllers)
|
var kvp = Assert.Single(parameterModel.Properties);
|
||||||
{
|
Assert.Equal("TestProperty", kvp.Key);
|
||||||
foreach (var action in controller.Actions)
|
Assert.Equal("TestValue", kvp.Value);
|
||||||
{
|
|
||||||
foreach (var parameter in action.Parameters)
|
|
||||||
{
|
|
||||||
var kvp = Assert.Single(parameter.Properties);
|
|
||||||
Assert.Equal("TestProperty", kvp.Key);
|
|
||||||
Assert.Equal("TestValue", kvp.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -47,8 +46,28 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var app = new ApplicationModel();
|
var app = new ApplicationModel();
|
||||||
app.Controllers.Add(new ControllerModel(typeof(HelloController).GetTypeInfo(), new List<object>()));
|
var controllerType1 = typeof(HelloController).GetTypeInfo();
|
||||||
app.Controllers.Add(new ControllerModel(typeof(WorldController).GetTypeInfo(), new List<object>()));
|
var actionMethod1 = controllerType1.GetMethod(nameof(HelloController.GetHello));
|
||||||
|
var controllerModel1 = new ControllerModel(controllerType1, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Actions =
|
||||||
|
{
|
||||||
|
new ActionModel(actionMethod1, Array.Empty<object>()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var controllerType2 = typeof(WorldController).GetTypeInfo();
|
||||||
|
var actionMethod2 = controllerType2.GetMethod(nameof(WorldController.GetWorld));
|
||||||
|
var controllerModel2 = new ControllerModel(controllerType2, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Actions =
|
||||||
|
{
|
||||||
|
new ActionModel(actionMethod2, Array.Empty<object>()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
app.Controllers.Add(controllerModel1);
|
||||||
|
app.Controllers.Add(controllerModel2);
|
||||||
|
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
options.Conventions.Add(new SimpleActionConvention());
|
options.Conventions.Add(new SimpleActionConvention());
|
||||||
|
|
@ -57,15 +76,76 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
options.Conventions[0].Apply(app);
|
options.Conventions[0].Apply(app);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
foreach (var controller in app.Controllers)
|
var kvp = Assert.Single(controllerModel1.Actions[0].Properties);
|
||||||
|
Assert.Equal("TestProperty", kvp.Key);
|
||||||
|
Assert.Equal("TestValue", kvp.Value);
|
||||||
|
|
||||||
|
kvp = Assert.Single(controllerModel2.Actions[0].Properties);
|
||||||
|
Assert.Equal("TestProperty", kvp.Key);
|
||||||
|
Assert.Equal("TestValue", kvp.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddedParameterConvention_AppliesToAllPropertiesAndParameters()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var app = new ApplicationModel();
|
||||||
|
var controllerType1 = typeof(HelloController).GetTypeInfo();
|
||||||
|
var parameterModel1 = new ParameterModel(
|
||||||
|
controllerType1.GetMethod(nameof(HelloController.GetInfo)).GetParameters()[0],
|
||||||
|
Array.Empty<object>());
|
||||||
|
var actionMethod1 = controllerType1.GetMethod(nameof(HelloController.GetInfo));
|
||||||
|
var property1 = controllerType1.GetProperty(nameof(HelloController.Property1));
|
||||||
|
var controllerModel1 = new ControllerModel(controllerType1, Array.Empty<object>())
|
||||||
{
|
{
|
||||||
foreach (var action in controller.Actions)
|
ControllerProperties =
|
||||||
{
|
{
|
||||||
var kvp = Assert.Single(action.Properties);
|
new PropertyModel(property1, Array.Empty<object>()),
|
||||||
Assert.Equal("TestProperty", kvp.Key);
|
},
|
||||||
Assert.Equal("TestValue", kvp.Value);
|
Actions =
|
||||||
|
{
|
||||||
|
new ActionModel(actionMethod1, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Parameters =
|
||||||
|
{
|
||||||
|
parameterModel1,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
var controllerType2 = typeof(WorldController).GetTypeInfo();
|
||||||
|
var property2 = controllerType2.GetProperty(nameof(WorldController.Property2));
|
||||||
|
var controllerModel2 = new ControllerModel(controllerType2, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
ControllerProperties =
|
||||||
|
{
|
||||||
|
new PropertyModel(property2, Array.Empty<object>()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
app.Controllers.Add(controllerModel1);
|
||||||
|
app.Controllers.Add(controllerModel2);
|
||||||
|
|
||||||
|
var options = new MvcOptions();
|
||||||
|
var convention = new SimplePropertyConvention();
|
||||||
|
options.Conventions.Add(convention);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
ApplicationModelConventions.ApplyConventions(app, options.Conventions);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var kvp = Assert.Single(controllerModel1.ControllerProperties[0].Properties);
|
||||||
|
Assert.Equal("TestProperty", kvp.Key);
|
||||||
|
Assert.Equal("TestValue", kvp.Value);
|
||||||
|
|
||||||
|
kvp = Assert.Single(controllerModel2.ControllerProperties[0].Properties);
|
||||||
|
Assert.Equal("TestProperty", kvp.Key);
|
||||||
|
Assert.Equal("TestValue", kvp.Value);
|
||||||
|
|
||||||
|
kvp = Assert.Single(controllerModel1.Actions[0].Parameters[0].Properties);
|
||||||
|
Assert.Equal("TestProperty", kvp.Key);
|
||||||
|
Assert.Equal("TestValue", kvp.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -74,8 +154,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
// Arrange
|
// Arrange
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
var app = new ApplicationModel();
|
var app = new ApplicationModel();
|
||||||
app.Controllers.Add(new ControllerModel(typeof(HelloController).GetTypeInfo(), new List<object>()));
|
app.Controllers.Add(new ControllerModel(typeof(HelloController).GetTypeInfo(), Array.Empty<object>()));
|
||||||
app.Controllers.Add(new ControllerModel(typeof(WorldController).GetTypeInfo(), new List<object>()));
|
app.Controllers.Add(new ControllerModel(typeof(WorldController).GetTypeInfo(), Array.Empty<object>()));
|
||||||
options.Conventions.Add(new SimpleControllerConvention());
|
options.Conventions.Add(new SimpleControllerConvention());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -115,7 +195,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
// Arrange
|
// Arrange
|
||||||
var applicationModel = new ApplicationModel();
|
var applicationModel = new ApplicationModel();
|
||||||
applicationModel.Controllers.Add(
|
applicationModel.Controllers.Add(
|
||||||
new ControllerModel(typeof(HelloController).GetTypeInfo(), new List<object>())
|
new ControllerModel(typeof(HelloController).GetTypeInfo(), Array.Empty<object>())
|
||||||
{
|
{
|
||||||
Application = applicationModel
|
Application = applicationModel
|
||||||
});
|
});
|
||||||
|
|
@ -128,18 +208,36 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplicationModelConventions_CopiesControllerModelCollectionOnApply_WhenRegisteredAsAnAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var controllerModelConvention = new ControllerModelCollectionModifyingConvention();
|
||||||
|
var applicationModel = new ApplicationModel();
|
||||||
|
applicationModel.Controllers.Add(
|
||||||
|
new ControllerModel(typeof(HelloController).GetTypeInfo(), new[] { controllerModelConvention })
|
||||||
|
{
|
||||||
|
Application = applicationModel
|
||||||
|
});
|
||||||
|
|
||||||
|
var conventions = new List<IApplicationModelConvention>();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplicationModelConventions_CopiesActionModelCollectionOnApply()
|
public void ApplicationModelConventions_CopiesActionModelCollectionOnApply()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var controllerType = typeof(HelloController).GetTypeInfo();
|
var controllerType = typeof(HelloController).GetTypeInfo();
|
||||||
var applicationModel = new ApplicationModel();
|
var applicationModel = new ApplicationModel();
|
||||||
var controllerModel = new ControllerModel(controllerType, new List<object>())
|
var controllerModel = new ControllerModel(controllerType, Array.Empty<object>())
|
||||||
{
|
{
|
||||||
Application = applicationModel
|
Application = applicationModel
|
||||||
};
|
};
|
||||||
controllerModel.Actions.Add(
|
controllerModel.Actions.Add(
|
||||||
new ActionModel(controllerType.GetMethod(nameof(HelloController.GetHello)), new List<object>())
|
new ActionModel(controllerType.GetMethod(nameof(HelloController.GetHello)), Array.Empty<object>())
|
||||||
{
|
{
|
||||||
Controller = controllerModel
|
Controller = controllerModel
|
||||||
});
|
});
|
||||||
|
|
@ -153,25 +251,74 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplicationModelConventions_CopiesPropertyModelCollectionOnApply()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var controllerType = typeof(HelloController).GetTypeInfo();
|
||||||
|
var applicationModel = new ApplicationModel();
|
||||||
|
var controllerModel = new ControllerModel(controllerType, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Application = applicationModel
|
||||||
|
};
|
||||||
|
controllerModel.ControllerProperties.Add(
|
||||||
|
new PropertyModel(controllerType.GetProperty(nameof(HelloController.Property1)), Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Controller = controllerModel
|
||||||
|
});
|
||||||
|
applicationModel.Controllers.Add(controllerModel);
|
||||||
|
|
||||||
|
var propertyModelConvention = new ParameterModelBaseConvention();
|
||||||
|
var conventions = new List<IApplicationModelConvention>();
|
||||||
|
conventions.Add(propertyModelConvention);
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplicationModelConventions_CopiesPropertyModelCollectionOnApply_WhenAppliedViaAttributes()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var propertyModelConvention = new ParameterModelBaseConvention();
|
||||||
|
var controllerType = typeof(HelloController).GetTypeInfo();
|
||||||
|
var applicationModel = new ApplicationModel();
|
||||||
|
var controllerModel = new ControllerModel(controllerType, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Application = applicationModel
|
||||||
|
};
|
||||||
|
controllerModel.ControllerProperties.Add(
|
||||||
|
new PropertyModel(controllerType.GetProperty(nameof(HelloController.Property1)), new[] { propertyModelConvention })
|
||||||
|
{
|
||||||
|
Controller = controllerModel
|
||||||
|
});
|
||||||
|
applicationModel.Controllers.Add(controllerModel);
|
||||||
|
|
||||||
|
var conventions = new List<IApplicationModelConvention>();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
ApplicationModelConventions.ApplyConventions(applicationModel, conventions);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ApplicationModelConventions_CopiesParameterModelCollectionOnApply()
|
public void ApplicationModelConventions_CopiesParameterModelCollectionOnApply()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var controllerType = typeof(HelloController).GetTypeInfo();
|
var controllerType = typeof(HelloController).GetTypeInfo();
|
||||||
var app = new ApplicationModel();
|
var app = new ApplicationModel();
|
||||||
var controllerModel = new ControllerModel(controllerType, new List<object>())
|
var controllerModel = new ControllerModel(controllerType, Array.Empty<object>())
|
||||||
{
|
{
|
||||||
Application = app
|
Application = app
|
||||||
};
|
};
|
||||||
app.Controllers.Add(controllerModel);
|
app.Controllers.Add(controllerModel);
|
||||||
var actionModel = new ActionModel(controllerType.GetMethod(nameof(HelloController.GetInfo)), new List<object>())
|
var actionModel = new ActionModel(controllerType.GetMethod(nameof(HelloController.GetInfo)), Array.Empty<object>())
|
||||||
{
|
{
|
||||||
Controller = controllerModel
|
Controller = controllerModel
|
||||||
};
|
};
|
||||||
controllerModel.Actions.Add(actionModel);
|
controllerModel.Actions.Add(actionModel);
|
||||||
var parameterModel = new ParameterModel(
|
var parameterModel = new ParameterModel(
|
||||||
controllerType.GetMethod(nameof(HelloController.GetInfo)).GetParameters()[0],
|
controllerType.GetMethod(nameof(HelloController.GetInfo)).GetParameters()[0],
|
||||||
new List<object>())
|
Array.Empty<object>())
|
||||||
{
|
{
|
||||||
Action = actionModel
|
Action = actionModel
|
||||||
};
|
};
|
||||||
|
|
@ -185,6 +332,37 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
ApplicationModelConventions.ApplyConventions(app, conventions);
|
ApplicationModelConventions.ApplyConventions(app, conventions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplicationModelConventions_CopiesParameterModelCollectionOnApply_WhenRegisteredViaAttribute()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var parameterModelConvention = new ParameterModelCollectionModifyingConvention();
|
||||||
|
var controllerType = typeof(HelloController).GetTypeInfo();
|
||||||
|
var app = new ApplicationModel();
|
||||||
|
var controllerModel = new ControllerModel(controllerType, Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Application = app
|
||||||
|
};
|
||||||
|
app.Controllers.Add(controllerModel);
|
||||||
|
var actionModel = new ActionModel(controllerType.GetMethod(nameof(HelloController.GetInfo)), Array.Empty<object>())
|
||||||
|
{
|
||||||
|
Controller = controllerModel
|
||||||
|
};
|
||||||
|
controllerModel.Actions.Add(actionModel);
|
||||||
|
var parameterModel = new ParameterModel(
|
||||||
|
controllerType.GetMethod(nameof(HelloController.GetInfo)).GetParameters()[0],
|
||||||
|
new[] { parameterModelConvention })
|
||||||
|
{
|
||||||
|
Action = actionModel
|
||||||
|
};
|
||||||
|
actionModel.Parameters.Add(parameterModel);
|
||||||
|
|
||||||
|
var conventions = new List<IApplicationModelConvention>();
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
ApplicationModelConventions.ApplyConventions(app, conventions);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GenericRemoveType_RemovesAllOfType()
|
public void GenericRemoveType_RemovesAllOfType()
|
||||||
{
|
{
|
||||||
|
|
@ -222,6 +400,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
||||||
private class HelloController
|
private class HelloController
|
||||||
{
|
{
|
||||||
|
public string Property1 { get; set; }
|
||||||
|
|
||||||
public string GetHello()
|
public string GetHello()
|
||||||
{
|
{
|
||||||
return "Hello";
|
return "Hello";
|
||||||
|
|
@ -235,6 +415,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
||||||
private class WorldController
|
private class WorldController
|
||||||
{
|
{
|
||||||
|
public string Property2 { get; set; }
|
||||||
|
|
||||||
public string GetWorld()
|
public string GetWorld()
|
||||||
{
|
{
|
||||||
return "World!";
|
return "World!";
|
||||||
|
|
@ -257,6 +439,14 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SimplePropertyConvention : IParameterModelBaseConvention
|
||||||
|
{
|
||||||
|
public void Apply(ParameterModelBase action)
|
||||||
|
{
|
||||||
|
action.Properties.Add("TestProperty", "TestValue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class SimpleControllerConvention : IControllerModelConvention
|
private class SimpleControllerConvention : IControllerModelConvention
|
||||||
{
|
{
|
||||||
public void Apply(ControllerModel controller)
|
public void Apply(ControllerModel controller)
|
||||||
|
|
@ -289,6 +479,15 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ParameterModelBaseConvention : IParameterModelBaseConvention
|
||||||
|
{
|
||||||
|
public void Apply(ParameterModelBase modelBase)
|
||||||
|
{
|
||||||
|
var property = (PropertyModel)modelBase;
|
||||||
|
property.Controller.ControllerProperties.Remove(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ParameterModelCollectionModifyingConvention : IParameterModelConvention
|
private class ParameterModelCollectionModifyingConvention : IParameterModelConvention
|
||||||
{
|
{
|
||||||
public void Apply(ParameterModel parameter)
|
public void Apply(ParameterModel parameter)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -28,8 +30,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
var provider2 = new Mock<IPageApplicationModelProvider>();
|
var provider2 = new Mock<IPageApplicationModelProvider>();
|
||||||
|
|
||||||
var sequence = 0;
|
var sequence = 0;
|
||||||
var pageApplicationModel1 = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), new object[0]);
|
var pageApplicationModel1 = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
var pageApplicationModel2 = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), new object[0]);
|
var pageApplicationModel2 = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
|
||||||
provider1.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
|
provider1.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
|
||||||
.Callback((PageApplicationModelProviderContext c) =>
|
.Callback((PageApplicationModelProviderContext c) =>
|
||||||
|
|
@ -103,7 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
.Callback((PageApplicationModelProviderContext c) =>
|
.Callback((PageApplicationModelProviderContext c) =>
|
||||||
{
|
{
|
||||||
Assert.Equal(1, sequence++);
|
Assert.Equal(1, sequence++);
|
||||||
c.PageApplicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), new object[0]);
|
c.PageApplicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
})
|
})
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
|
|
@ -148,45 +150,346 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Load_InvokesApplicationModelConventions()
|
public void ApplyConventions_InvokesApplicationModelConventions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var descriptor = new PageActionDescriptor();
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var model = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
|
||||||
var compilerProvider = GetCompilerProvider();
|
|
||||||
|
|
||||||
var model = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), new object[0]);
|
|
||||||
var provider = new Mock<IPageApplicationModelProvider>();
|
|
||||||
provider.Setup(p => p.OnProvidersExecuting(It.IsAny<PageApplicationModelProviderContext>()))
|
|
||||||
.Callback((PageApplicationModelProviderContext c) =>
|
|
||||||
{
|
|
||||||
c.PageApplicationModel = model;
|
|
||||||
});
|
|
||||||
var providers = new[] { provider.Object };
|
|
||||||
|
|
||||||
var razorPagesOptions = Options.Create(new RazorPagesOptions());
|
|
||||||
var mvcOptions = Options.Create(new MvcOptions());
|
|
||||||
var convention = new Mock<IPageApplicationModelConvention>();
|
var convention = new Mock<IPageApplicationModelConvention>();
|
||||||
convention.Setup(c => c.Apply(It.IsAny<PageApplicationModel>()))
|
convention.Setup(c => c.Apply(It.IsAny<PageApplicationModel>()))
|
||||||
.Callback((PageApplicationModel m) =>
|
.Callback((PageApplicationModel m) =>
|
||||||
{
|
{
|
||||||
Assert.Same(model, m);
|
Assert.Same(model, m);
|
||||||
});
|
})
|
||||||
razorPagesOptions.Value.Conventions.Add(convention.Object);
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection
|
||||||
var loader = new DefaultPageLoader(
|
{
|
||||||
providers,
|
convention.Object,
|
||||||
compilerProvider,
|
};
|
||||||
razorPagesOptions,
|
|
||||||
mvcOptions);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = loader.Load(new PageActionDescriptor());
|
DefaultPageLoader.ApplyConventions(conventionCollection, model);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
convention.Verify();
|
convention.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesApplicationModelConventions_SpecifiedOnHandlerType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var handlerConvention = new Mock<IPageApplicationModelConvention>();
|
||||||
|
var model = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), new[] { handlerConvention.Object });
|
||||||
|
|
||||||
|
var globalConvention = new Mock<IPageApplicationModelConvention>();
|
||||||
|
globalConvention.Setup(c => c.Apply(It.IsAny<PageApplicationModel>()))
|
||||||
|
.Callback((PageApplicationModel m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(model, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
handlerConvention.Setup(c => c.Apply(It.IsAny<PageApplicationModel>()))
|
||||||
|
.Callback((PageApplicationModel m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(model, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection
|
||||||
|
{
|
||||||
|
globalConvention.Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, model);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
globalConvention.Verify();
|
||||||
|
handlerConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesHandlerModelConventions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var handlerModelConvention = new Mock<IPageHandlerModelConvention>();
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, new[] { handlerModelConvention.Object });
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
|
||||||
|
handlerModelConvention.Setup(p => p.Apply(It.IsAny<PageHandlerModel>()))
|
||||||
|
.Callback((PageHandlerModel m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(handlerModel, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handlerModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesHandlerModelConventions_DefinedGlobally()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, Array.Empty<object>());
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
|
||||||
|
var handlerModelConvention = new Mock<IPageHandlerModelConvention>();
|
||||||
|
handlerModelConvention.Setup(p => p.Apply(It.IsAny<PageHandlerModel>()))
|
||||||
|
.Callback((PageHandlerModel m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(handlerModel, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection { handlerModelConvention.Object };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handlerModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_RemovingHandlerAsPartOfHandlerModelConvention_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var handlerModelConvention = new Mock<IPageHandlerModelConvention>();
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, new[] { handlerModelConvention.Object })
|
||||||
|
{
|
||||||
|
Page = applicationModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
|
||||||
|
handlerModelConvention.Setup(p => p.Apply(It.IsAny<PageHandlerModel>()))
|
||||||
|
.Callback((PageHandlerModel m) =>
|
||||||
|
{
|
||||||
|
m.Page.HandlerMethods.Remove(m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
handlerModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesParameterModelConventions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var parameterInfo = methodInfo.GetParameters()[0];
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, Array.Empty<object>());
|
||||||
|
var parameterModelConvention = new Mock<IParameterModelBaseConvention>();
|
||||||
|
var parameterModel = new PageParameterModel(parameterInfo, new[] { parameterModelConvention.Object });
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
handlerModel.Parameters.Add(parameterModel);
|
||||||
|
|
||||||
|
parameterModelConvention.Setup(p => p.Apply(It.IsAny<ParameterModelBase>()))
|
||||||
|
.Callback((ParameterModelBase m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(parameterModel, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
parameterModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesParameterModelConventions_DeclaredGlobally()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var parameterInfo = methodInfo.GetParameters()[0];
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, Array.Empty<object>());
|
||||||
|
var parameterModel = new PageParameterModel(parameterInfo, Array.Empty<object>());
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
handlerModel.Parameters.Add(parameterModel);
|
||||||
|
|
||||||
|
var parameterModelConvention = new Mock<IParameterModelBaseConvention>();
|
||||||
|
parameterModelConvention.Setup(p => p.Apply(It.IsAny<ParameterModelBase>()))
|
||||||
|
.Callback((ParameterModelBase m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(parameterModel, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection { parameterModelConvention.Object };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
parameterModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_RemovingParameterModelAsPartOfConventionWorks()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var parameterInfo = methodInfo.GetParameters()[0];
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, Array.Empty<object>());
|
||||||
|
var parameterModelConvention = new Mock<IParameterModelBaseConvention>();
|
||||||
|
var parameterModel = new PageParameterModel(parameterInfo, new[] { parameterModelConvention.Object })
|
||||||
|
{
|
||||||
|
Handler = handlerModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
handlerModel.Parameters.Add(parameterModel);
|
||||||
|
|
||||||
|
parameterModelConvention.Setup(p => p.Apply(It.IsAny<ParameterModelBase>()))
|
||||||
|
.Callback((ParameterModelBase m) =>
|
||||||
|
{
|
||||||
|
var model = Assert.IsType<PageParameterModel>(m);
|
||||||
|
model.Handler.Parameters.Remove(model);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
parameterModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesPropertyModelConventions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var propertyInfo = GetType().GetProperty(nameof(TestProperty), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var parameterInfo = methodInfo.GetParameters()[0];
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, Array.Empty<object>());
|
||||||
|
var parameterModel = new PageParameterModel(parameterInfo, Array.Empty<object>());
|
||||||
|
var propertyModelConvention = new Mock<IParameterModelBaseConvention>();
|
||||||
|
var propertyModel = new PagePropertyModel(propertyInfo, new[] { propertyModelConvention.Object });
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
applicationModel.HandlerProperties.Add(propertyModel);
|
||||||
|
handlerModel.Parameters.Add(parameterModel);
|
||||||
|
|
||||||
|
propertyModelConvention.Setup(p => p.Apply(It.IsAny<ParameterModelBase>()))
|
||||||
|
.Callback((ParameterModelBase m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(propertyModel, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
propertyModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_InvokesPropertyModelConventions_DeclaredGlobally()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var methodInfo = GetType().GetMethod(nameof(OnGet), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
var propertyInfo = GetType().GetProperty(nameof(TestProperty), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var handlerModel = new PageHandlerModel(methodInfo, Array.Empty<object>());
|
||||||
|
var propertyModel = new PagePropertyModel(propertyInfo, Array.Empty<object>());
|
||||||
|
|
||||||
|
applicationModel.HandlerMethods.Add(handlerModel);
|
||||||
|
applicationModel.HandlerProperties.Add(propertyModel);
|
||||||
|
|
||||||
|
var propertyModelConvention = new Mock<IParameterModelBaseConvention>();
|
||||||
|
propertyModelConvention.Setup(p => p.Apply(It.IsAny<ParameterModelBase>()))
|
||||||
|
.Callback((ParameterModelBase m) =>
|
||||||
|
{
|
||||||
|
Assert.Same(propertyModel, m);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection { propertyModelConvention.Object };
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
propertyModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyConventions_RemovingPropertyModelAsPartOfConvention_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var descriptor = new PageActionDescriptor();
|
||||||
|
var propertyInfo = GetType().GetProperty(nameof(TestProperty), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
var applicationModel = new PageApplicationModel(descriptor, typeof(object).GetTypeInfo(), Array.Empty<object>());
|
||||||
|
var propertyModelConvention = new Mock<IParameterModelBaseConvention>();
|
||||||
|
var propertyModel = new PagePropertyModel(propertyInfo, new[] { propertyModelConvention.Object })
|
||||||
|
{
|
||||||
|
Page = applicationModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
applicationModel.HandlerProperties.Add(propertyModel);
|
||||||
|
|
||||||
|
propertyModelConvention.Setup(p => p.Apply(It.IsAny<ParameterModelBase>()))
|
||||||
|
.Callback((ParameterModelBase m) =>
|
||||||
|
{
|
||||||
|
var model = Assert.IsType<PagePropertyModel>(m);
|
||||||
|
model.Page.HandlerProperties.Remove(model);
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
var conventionCollection = new PageConventionCollection();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
DefaultPageLoader.ApplyConventions(conventionCollection, applicationModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
propertyModelConvention.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
private static IViewCompilerProvider GetCompilerProvider()
|
private static IViewCompilerProvider GetCompilerProvider()
|
||||||
{
|
{
|
||||||
var descriptor = new CompiledViewDescriptor
|
var descriptor = new CompiledViewDescriptor
|
||||||
|
|
@ -202,5 +505,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
||||||
.Returns(compiler.Object);
|
.Returns(compiler.Object);
|
||||||
return compilerProvider.Object;
|
return compilerProvider.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGet(string parameter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private string TestProperty { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue