Introduce IPageApplicationModelPartsProvider (#9066)
* Resolved #6919. It might be required to rework unit tests.
This commit is contained in:
parent
3fbf3ac791
commit
1d5d144c12
|
|
@ -18,6 +18,13 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
{
|
||||
void Apply(Microsoft.AspNetCore.Mvc.ApplicationModels.PageApplicationModel model);
|
||||
}
|
||||
public partial interface IPageApplicationModelPartsProvider
|
||||
{
|
||||
Microsoft.AspNetCore.Mvc.ApplicationModels.PageHandlerModel CreateHandlerModel(System.Reflection.MethodInfo method);
|
||||
Microsoft.AspNetCore.Mvc.ApplicationModels.PageParameterModel CreateParameterModel(System.Reflection.ParameterInfo parameter);
|
||||
Microsoft.AspNetCore.Mvc.ApplicationModels.PagePropertyModel CreatePropertyModel(System.Reflection.PropertyInfo property);
|
||||
bool IsHandler(System.Reflection.MethodInfo methodInfo);
|
||||
}
|
||||
public partial interface IPageApplicationModelProvider
|
||||
{
|
||||
int Order { get; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,276 @@
|
|||
// 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.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||
{
|
||||
internal class DefaultPageApplicationModelPartsProvider: IPageApplicationModelPartsProvider
|
||||
{
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
|
||||
private readonly Func<ActionContext, bool> _supportsAllRequests;
|
||||
private readonly Func<ActionContext, bool> _supportsNonGetRequests;
|
||||
|
||||
|
||||
public DefaultPageApplicationModelPartsProvider(IModelMetadataProvider modelMetadataProvider)
|
||||
{
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
|
||||
_supportsAllRequests = _ => true;
|
||||
_supportsNonGetRequests = context => !HttpMethods.IsGet(context.HttpContext.Request.Method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PageHandlerModel"/> for the specified <paramref name="method"/>.s
|
||||
/// </summary>
|
||||
/// <param name="method">The <see cref="MethodInfo"/>.</param>
|
||||
/// <returns>The <see cref="PageHandlerModel"/>.</returns>
|
||||
public PageHandlerModel CreateHandlerModel(MethodInfo method)
|
||||
{
|
||||
if (method == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(method));
|
||||
}
|
||||
|
||||
if (!IsHandler(method))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!TryParseHandlerMethod(method.Name, out var httpMethod, out var handlerName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var handlerModel = new PageHandlerModel(
|
||||
method,
|
||||
method.GetCustomAttributes(inherit: true))
|
||||
{
|
||||
Name = method.Name,
|
||||
HandlerName = handlerName,
|
||||
HttpMethod = httpMethod,
|
||||
};
|
||||
|
||||
var methodParameters = handlerModel.MethodInfo.GetParameters();
|
||||
|
||||
for (var i = 0; i < methodParameters.Length; i++)
|
||||
{
|
||||
var parameter = methodParameters[i];
|
||||
var parameterModel = CreateParameterModel(parameter);
|
||||
parameterModel.Handler = handlerModel;
|
||||
|
||||
handlerModel.Parameters.Add(parameterModel);
|
||||
}
|
||||
|
||||
return handlerModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PageParameterModel"/> for the specified <paramref name="parameter"/>.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The <see cref="ParameterInfo"/>.</param>
|
||||
/// <returns>The <see cref="PageParameterModel"/>.</returns>
|
||||
public PageParameterModel CreateParameterModel(ParameterInfo parameter)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(parameter));
|
||||
}
|
||||
|
||||
var attributes = parameter.GetCustomAttributes(inherit: true);
|
||||
|
||||
BindingInfo bindingInfo;
|
||||
if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
{
|
||||
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
|
||||
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
bindingInfo = BindingInfo.GetBindingInfo(attributes);
|
||||
}
|
||||
|
||||
return new PageParameterModel(parameter, attributes)
|
||||
{
|
||||
BindingInfo = bindingInfo,
|
||||
ParameterName = parameter.Name,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PagePropertyModel"/> for the <paramref name="property"/>.
|
||||
/// </summary>
|
||||
/// <param name="property">The <see cref="PropertyInfo"/>.</param>
|
||||
/// <returns>The <see cref="PagePropertyModel"/>.</returns>
|
||||
public PagePropertyModel CreatePropertyModel(PropertyInfo property)
|
||||
{
|
||||
if (property == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(property));
|
||||
}
|
||||
|
||||
var propertyAttributes = property.GetCustomAttributes(inherit: true);
|
||||
|
||||
// BindingInfo for properties can be either specified by decorating the property with binding-specific attributes.
|
||||
// ModelMetadata also adds information from the property's type and any configured IBindingMetadataProvider.
|
||||
var propertyMetadata = _modelMetadataProvider.GetMetadataForProperty(property.DeclaringType, property.Name);
|
||||
var bindingInfo = BindingInfo.GetBindingInfo(propertyAttributes, propertyMetadata);
|
||||
|
||||
if (bindingInfo == null)
|
||||
{
|
||||
// Look for BindPropertiesAttribute on the handler type if no BindingInfo was inferred for the property.
|
||||
// This allows a user to enable model binding on properties by decorating the controller type with BindPropertiesAttribute.
|
||||
var declaringType = property.DeclaringType;
|
||||
var bindPropertiesAttribute = declaringType.GetCustomAttribute<BindPropertiesAttribute>(inherit: true);
|
||||
if (bindPropertiesAttribute != null)
|
||||
{
|
||||
var requestPredicate = bindPropertiesAttribute.SupportsGet ? _supportsAllRequests : _supportsNonGetRequests;
|
||||
bindingInfo = new BindingInfo
|
||||
{
|
||||
RequestPredicate = requestPredicate,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var model = new PagePropertyModel(property, propertyAttributes)
|
||||
{
|
||||
PropertyName = property.Name,
|
||||
BindingInfo = bindingInfo,
|
||||
};
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the specified <paramref name="methodInfo"/> is a handler.
|
||||
/// </summary>
|
||||
/// <param name="methodInfo">The <see cref="MethodInfo"/>.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="methodInfo"/> is a handler. Otherwise <c>false</c>.</returns>
|
||||
/// <remarks>
|
||||
/// Override this method to provide custom logic to determine which methods are considered handlers.
|
||||
/// </remarks>
|
||||
public bool IsHandler(MethodInfo methodInfo)
|
||||
{
|
||||
// The SpecialName bit is set to flag members that are treated in a special way by some compilers
|
||||
// (such as property accessors and operator overloading methods).
|
||||
if (methodInfo.IsSpecialName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Overridden methods from Object class, e.g. Equals(Object), GetHashCode(), etc., are not valid.
|
||||
if (methodInfo.GetBaseDefinition().DeclaringType == typeof(object))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsAbstract)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsConstructor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsGenericMethod)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!methodInfo.IsPublic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsDefined(typeof(NonHandlerAttribute)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude the whole hierarchy of Page.
|
||||
var declaringType = methodInfo.DeclaringType;
|
||||
if (declaringType == typeof(Page) ||
|
||||
declaringType == typeof(PageBase) ||
|
||||
declaringType == typeof(RazorPageBase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude methods declared on PageModel
|
||||
if (declaringType == typeof(PageModel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool TryParseHandlerMethod(string methodName, out string httpMethod, out string handler)
|
||||
{
|
||||
httpMethod = null;
|
||||
handler = null;
|
||||
|
||||
// Handler method names always start with "On"
|
||||
if (!methodName.StartsWith("On") || methodName.Length <= "On".Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we parse the method name according to our conventions to determine the required HTTP method
|
||||
// and optional 'handler name'.
|
||||
//
|
||||
// Valid names look like:
|
||||
// - OnGet
|
||||
// - OnPost
|
||||
// - OnFooBar
|
||||
// - OnTraceAsync
|
||||
// - OnPostEditAsync
|
||||
|
||||
var start = "On".Length;
|
||||
var length = methodName.Length;
|
||||
if (methodName.EndsWith("Async", StringComparison.Ordinal))
|
||||
{
|
||||
length -= "Async".Length;
|
||||
}
|
||||
|
||||
if (start == length)
|
||||
{
|
||||
// There are no additional characters. This is "On" or "OnAsync".
|
||||
return false;
|
||||
}
|
||||
|
||||
// The http method follows "On" and is required to be at least one character. We use casing
|
||||
// to determine where it ends.
|
||||
var handlerNameStart = start + 1;
|
||||
for (; handlerNameStart < length; handlerNameStart++)
|
||||
{
|
||||
if (char.IsUpper(methodName[handlerNameStart]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
httpMethod = methodName.Substring(start, handlerNameStart - start);
|
||||
|
||||
// The handler name follows the http method and is optional. It includes everything up to the end
|
||||
// excluding the "Async" suffix (if present).
|
||||
handler = handlerNameStart == length ? null : methodName.Substring(handlerNameStart, length - handlerNameStart);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,19 +22,18 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
private readonly PageHandlerResultFilter _pageHandlerResultFilter = new PageHandlerResultFilter();
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
private readonly RazorPagesOptions _razorPagesOptions;
|
||||
private readonly Func<ActionContext, bool> _supportsAllRequests;
|
||||
private readonly Func<ActionContext, bool> _supportsNonGetRequests;
|
||||
private readonly IPageApplicationModelPartsProvider _pageApplicationModelPartsProvider;
|
||||
private readonly HandleOptionsRequestsPageFilter _handleOptionsRequestsFilter;
|
||||
|
||||
public DefaultPageApplicationModelProvider(
|
||||
IModelMetadataProvider modelMetadataProvider,
|
||||
IOptions<RazorPagesOptions> razorPagesOptions)
|
||||
IOptions<RazorPagesOptions> razorPagesOptions,
|
||||
IPageApplicationModelPartsProvider pageApplicationModelPartsProvider)
|
||||
{
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_razorPagesOptions = razorPagesOptions.Value;
|
||||
_pageApplicationModelPartsProvider = pageApplicationModelPartsProvider;
|
||||
|
||||
_supportsAllRequests = _ => true;
|
||||
_supportsNonGetRequests = context => !HttpMethods.IsGet(context.HttpContext.Request.Method);
|
||||
_handleOptionsRequestsFilter = new HandleOptionsRequestsPageFilter();
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +132,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
for (var i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var propertyModel = CreatePropertyModel(properties[i].Property);
|
||||
var propertyModel = _pageApplicationModelPartsProvider.CreatePropertyModel(properties[i].Property);
|
||||
if (propertyModel != null)
|
||||
{
|
||||
propertyModel.Page = pageModel;
|
||||
|
|
@ -149,7 +148,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
for (var i = 0; i < methods.Length; i++)
|
||||
{
|
||||
var handler = CreateHandlerModel(methods[i]);
|
||||
var handler = _pageApplicationModelPartsProvider.CreateHandlerModel(methods[i]);
|
||||
if (handler != null)
|
||||
{
|
||||
pageModel.HandlerMethods.Add(handler);
|
||||
|
|
@ -181,250 +180,5 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
pageModel.Filters.Add(_handleOptionsRequestsFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PageHandlerModel"/> for the specified <paramref name="method"/>.s
|
||||
/// </summary>
|
||||
/// <param name="method">The <see cref="MethodInfo"/>.</param>
|
||||
/// <returns>The <see cref="PageHandlerModel"/>.</returns>
|
||||
protected virtual PageHandlerModel CreateHandlerModel(MethodInfo method)
|
||||
{
|
||||
if (method == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(method));
|
||||
}
|
||||
|
||||
if (!IsHandler(method))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!TryParseHandlerMethod(method.Name, out var httpMethod, out var handlerName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var handlerModel = new PageHandlerModel(
|
||||
method,
|
||||
method.GetCustomAttributes(inherit: true))
|
||||
{
|
||||
Name = method.Name,
|
||||
HandlerName = handlerName,
|
||||
HttpMethod = httpMethod,
|
||||
};
|
||||
|
||||
var methodParameters = handlerModel.MethodInfo.GetParameters();
|
||||
|
||||
for (var i = 0; i < methodParameters.Length; i++)
|
||||
{
|
||||
var parameter = methodParameters[i];
|
||||
var parameterModel = CreateParameterModel(parameter);
|
||||
parameterModel.Handler = handlerModel;
|
||||
|
||||
handlerModel.Parameters.Add(parameterModel);
|
||||
}
|
||||
|
||||
return handlerModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PageParameterModel"/> for the specified <paramref name="parameter"/>.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The <see cref="ParameterInfo"/>.</param>
|
||||
/// <returns>The <see cref="PageParameterModel"/>.</returns>
|
||||
protected virtual PageParameterModel CreateParameterModel(ParameterInfo parameter)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(parameter));
|
||||
}
|
||||
|
||||
var attributes = parameter.GetCustomAttributes(inherit: true);
|
||||
|
||||
BindingInfo bindingInfo;
|
||||
if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
{
|
||||
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
|
||||
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
bindingInfo = BindingInfo.GetBindingInfo(attributes);
|
||||
}
|
||||
|
||||
return new PageParameterModel(parameter, attributes)
|
||||
{
|
||||
BindingInfo = bindingInfo,
|
||||
ParameterName = parameter.Name,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PagePropertyModel"/> for the <paramref name="property"/>.
|
||||
/// </summary>
|
||||
/// <param name="property">The <see cref="PropertyInfo"/>.</param>
|
||||
/// <returns>The <see cref="PagePropertyModel"/>.</returns>
|
||||
protected virtual PagePropertyModel CreatePropertyModel(PropertyInfo property)
|
||||
{
|
||||
if (property == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(property));
|
||||
}
|
||||
|
||||
var propertyAttributes = property.GetCustomAttributes(inherit: true);
|
||||
|
||||
// BindingInfo for properties can be either specified by decorating the property with binding-specific attributes.
|
||||
// ModelMetadata also adds information from the property's type and any configured IBindingMetadataProvider.
|
||||
var propertyMetadata = _modelMetadataProvider.GetMetadataForProperty(property.DeclaringType, property.Name);
|
||||
var bindingInfo = BindingInfo.GetBindingInfo(propertyAttributes, propertyMetadata);
|
||||
|
||||
if (bindingInfo == null)
|
||||
{
|
||||
// Look for BindPropertiesAttribute on the handler type if no BindingInfo was inferred for the property.
|
||||
// This allows a user to enable model binding on properties by decorating the controller type with BindPropertiesAttribute.
|
||||
var declaringType = property.DeclaringType;
|
||||
var bindPropertiesAttribute = declaringType.GetCustomAttribute<BindPropertiesAttribute>(inherit: true);
|
||||
if (bindPropertiesAttribute != null)
|
||||
{
|
||||
var requestPredicate = bindPropertiesAttribute.SupportsGet ? _supportsAllRequests : _supportsNonGetRequests;
|
||||
bindingInfo = new BindingInfo
|
||||
{
|
||||
RequestPredicate = requestPredicate,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var model = new PagePropertyModel(property, propertyAttributes)
|
||||
{
|
||||
PropertyName = property.Name,
|
||||
BindingInfo = bindingInfo,
|
||||
};
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the specified <paramref name="methodInfo"/> is a handler.
|
||||
/// </summary>
|
||||
/// <param name="methodInfo">The <see cref="MethodInfo"/>.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="methodInfo"/> is a handler. Otherwise <c>false</c>.</returns>
|
||||
/// <remarks>
|
||||
/// Override this method to provide custom logic to determine which methods are considered handlers.
|
||||
/// </remarks>
|
||||
protected virtual bool IsHandler(MethodInfo methodInfo)
|
||||
{
|
||||
// The SpecialName bit is set to flag members that are treated in a special way by some compilers
|
||||
// (such as property accessors and operator overloading methods).
|
||||
if (methodInfo.IsSpecialName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Overridden methods from Object class, e.g. Equals(Object), GetHashCode(), etc., are not valid.
|
||||
if (methodInfo.GetBaseDefinition().DeclaringType == typeof(object))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsStatic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsAbstract)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsConstructor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsGenericMethod)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!methodInfo.IsPublic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (methodInfo.IsDefined(typeof(NonHandlerAttribute)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude the whole hierarchy of Page.
|
||||
var declaringType = methodInfo.DeclaringType;
|
||||
if (declaringType == typeof(Page) ||
|
||||
declaringType == typeof(PageBase) ||
|
||||
declaringType == typeof(RazorPageBase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exclude methods declared on PageModel
|
||||
if (declaringType == typeof(PageModel))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool TryParseHandlerMethod(string methodName, out string httpMethod, out string handler)
|
||||
{
|
||||
httpMethod = null;
|
||||
handler = null;
|
||||
|
||||
// Handler method names always start with "On"
|
||||
if (!methodName.StartsWith("On") || methodName.Length <= "On".Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we parse the method name according to our conventions to determine the required HTTP method
|
||||
// and optional 'handler name'.
|
||||
//
|
||||
// Valid names look like:
|
||||
// - OnGet
|
||||
// - OnPost
|
||||
// - OnFooBar
|
||||
// - OnTraceAsync
|
||||
// - OnPostEditAsync
|
||||
|
||||
var start = "On".Length;
|
||||
var length = methodName.Length;
|
||||
if (methodName.EndsWith("Async", StringComparison.Ordinal))
|
||||
{
|
||||
length -= "Async".Length;
|
||||
}
|
||||
|
||||
if (start == length)
|
||||
{
|
||||
// There are no additional characters. This is "On" or "OnAsync".
|
||||
return false;
|
||||
}
|
||||
|
||||
// The http method follows "On" and is required to be at least one character. We use casing
|
||||
// to determine where it ends.
|
||||
var handlerNameStart = start + 1;
|
||||
for (; handlerNameStart < length; handlerNameStart++)
|
||||
{
|
||||
if (char.IsUpper(methodName[handlerNameStart]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
httpMethod = methodName.Substring(start, handlerNameStart - start);
|
||||
|
||||
// The handler name follows the http method and is optional. It includes everything up to the end
|
||||
// excluding the "Async" suffix (if present).
|
||||
handler = handlerNameStart == length ? null : methodName.Substring(handlerNameStart, length - handlerNameStart);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// 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.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides parts that are used to construct a <see cref="PageApplicationModel" /> instance
|
||||
/// </summary>
|
||||
public interface IPageApplicationModelPartsProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PageHandlerModel"/> for the specified <paramref name="method"/>.s
|
||||
/// </summary>
|
||||
/// <param name="method">The <see cref="MethodInfo"/>.</param>
|
||||
/// <returns>The <see cref="PageHandlerModel"/>.</returns>
|
||||
PageHandlerModel CreateHandlerModel(MethodInfo method);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PageParameterModel"/> for the specified <paramref name="parameter"/>.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The <see cref="ParameterInfo"/>.</param>
|
||||
/// <returns>The <see cref="PageParameterModel"/>.</returns>
|
||||
PageParameterModel CreateParameterModel(ParameterInfo parameter);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="PagePropertyModel"/> for the <paramref name="property"/>.
|
||||
/// </summary>
|
||||
/// <param name="property">The <see cref="PropertyInfo"/>.</param>
|
||||
/// <returns>The <see cref="PagePropertyModel"/>.</returns>
|
||||
PagePropertyModel CreatePropertyModel(PropertyInfo property);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the specified <paramref name="methodInfo"/> is a handler.
|
||||
/// </summary>
|
||||
/// <param name="methodInfo">The <see cref="MethodInfo"/>.</param>
|
||||
/// <returns><c>true</c> if the <paramref name="methodInfo"/> is a handler. Otherwise <c>false</c>.</returns>
|
||||
/// <remarks>
|
||||
/// Override this method to provide custom logic to determine which methods are considered handlers.
|
||||
/// </remarks>
|
||||
bool IsHandler(MethodInfo methodInfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +113,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Singleton<IPageApplicationModelProvider, ResponseCacheFilterApplicationModelProvider>());
|
||||
|
||||
services.TryAddSingleton<IPageApplicationModelPartsProvider, DefaultPageApplicationModelPartsProvider>();
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Singleton<IActionInvokerProvider, PageActionInvokerProvider>());
|
||||
|
||||
|
|
|
|||
|
|
@ -188,9 +188,12 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
private static PageApplicationModelProviderContext GetApplicationProviderContext(TypeInfo typeInfo)
|
||||
{
|
||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
|
||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new RazorPagesOptions()));
|
||||
modelMetadataProvider,
|
||||
Options.Create(new RazorPagesOptions()),
|
||||
new DefaultPageApplicationModelPartsProvider(modelMetadataProvider));
|
||||
|
||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||
defaultProvider.OnProvidersExecuting(context);
|
||||
|
|
|
|||
|
|
@ -971,7 +971,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
public void TryParseHandler_ParsesHandlerNames_InvalidData(string methodName)
|
||||
{
|
||||
// Act
|
||||
var result = DefaultPageApplicationModelProvider.TryParseHandlerMethod(methodName, out var httpMethod, out var handler);
|
||||
var result = DefaultPageApplicationModelPartsProvider.TryParseHandlerMethod(methodName, out var httpMethod, out var handler);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
|
|
@ -993,7 +993,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
// Arrange
|
||||
|
||||
// Act
|
||||
var result = DefaultPageApplicationModelProvider.TryParseHandlerMethod(methodName, out var httpMethod, out var handler);
|
||||
var result = DefaultPageApplicationModelPartsProvider.TryParseHandlerMethod(methodName, out var httpMethod, out var handler);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
|
|
@ -1169,9 +1169,12 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
private static DefaultPageApplicationModelProvider CreateProvider()
|
||||
{
|
||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
|
||||
return new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new RazorPagesOptions()));
|
||||
modelMetadataProvider,
|
||||
Options.Create(new RazorPagesOptions()),
|
||||
new DefaultPageApplicationModelPartsProvider(modelMetadataProvider));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,9 +142,12 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
|||
|
||||
private static PageApplicationModelProviderContext GetApplicationProviderContext(TypeInfo typeInfo)
|
||||
{
|
||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
|
||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new RazorPagesOptions()));
|
||||
modelMetadataProvider,
|
||||
Options.Create(new RazorPagesOptions()),
|
||||
new DefaultPageApplicationModelPartsProvider(modelMetadataProvider));
|
||||
|
||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||
defaultProvider.OnProvidersExecuting(context);
|
||||
|
|
|
|||
Loading…
Reference in New Issue