From 1d5d144c12d13b2672352e43ba883d5be3d95cf4 Mon Sep 17 00:00:00 2001 From: Martin Gubis <35179604+mgubis@users.noreply.github.com> Date: Tue, 23 Apr 2019 23:37:03 +0200 Subject: [PATCH] Introduce IPageApplicationModelPartsProvider (#9066) * Resolved #6919. It might be required to rework unit tests. --- ...AspNetCore.Mvc.RazorPages.netcoreapp3.0.cs | 7 + ...efaultPageApplicationModelPartsProvider.cs | 276 ++++++++++++++++++ .../DefaultPageApplicationModelProvider.cs | 258 +--------------- .../IPageApplicationModelPartsProvider.cs | 48 +++ .../MvcRazorPagesMvcCoreBuilderExtensions.cs | 2 + ...izationPageApplicationModelProviderTest.cs | 7 +- ...DefaultPageApplicationModelProviderTest.cs | 11 +- ...CacheFilterApplicationModelProviderTest.cs | 7 +- 8 files changed, 356 insertions(+), 260 deletions(-) create mode 100644 src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelPartsProvider.cs create mode 100644 src/Mvc/Mvc.RazorPages/src/ApplicationModels/IPageApplicationModelPartsProvider.cs diff --git a/src/Mvc/Mvc.RazorPages/ref/Microsoft.AspNetCore.Mvc.RazorPages.netcoreapp3.0.cs b/src/Mvc/Mvc.RazorPages/ref/Microsoft.AspNetCore.Mvc.RazorPages.netcoreapp3.0.cs index 6ced9ae64c..a13e7ad428 100644 --- a/src/Mvc/Mvc.RazorPages/ref/Microsoft.AspNetCore.Mvc.RazorPages.netcoreapp3.0.cs +++ b/src/Mvc/Mvc.RazorPages/ref/Microsoft.AspNetCore.Mvc.RazorPages.netcoreapp3.0.cs @@ -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; } diff --git a/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelPartsProvider.cs b/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelPartsProvider.cs new file mode 100644 index 0000000000..5fc10e4148 --- /dev/null +++ b/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelPartsProvider.cs @@ -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 _supportsAllRequests; + private readonly Func _supportsNonGetRequests; + + + public DefaultPageApplicationModelPartsProvider(IModelMetadataProvider modelMetadataProvider) + { + _modelMetadataProvider = modelMetadataProvider; + + _supportsAllRequests = _ => true; + _supportsNonGetRequests = context => !HttpMethods.IsGet(context.HttpContext.Request.Method); + } + + /// + /// Creates a for the specified .s + /// + /// The . + /// The . + 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; + } + + /// + /// Creates a for the specified . + /// + /// The . + /// The . + 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, + }; + } + + /// + /// Creates a for the . + /// + /// The . + /// The . + 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(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; + } + + /// + /// Determines if the specified is a handler. + /// + /// The . + /// true if the is a handler. Otherwise false. + /// + /// Override this method to provide custom logic to determine which methods are considered handlers. + /// + 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; + } + } +} diff --git a/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelProvider.cs b/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelProvider.cs index 32587f87af..c146407cf1 100644 --- a/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelProvider.cs +++ b/src/Mvc/Mvc.RazorPages/src/ApplicationModels/DefaultPageApplicationModelProvider.cs @@ -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 _supportsAllRequests; - private readonly Func _supportsNonGetRequests; + private readonly IPageApplicationModelPartsProvider _pageApplicationModelPartsProvider; private readonly HandleOptionsRequestsPageFilter _handleOptionsRequestsFilter; public DefaultPageApplicationModelProvider( IModelMetadataProvider modelMetadataProvider, - IOptions razorPagesOptions) + IOptions 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); } - - /// - /// Creates a for the specified .s - /// - /// The . - /// The . - 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; - } - - /// - /// Creates a for the specified . - /// - /// The . - /// The . - 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, - }; - } - - /// - /// Creates a for the . - /// - /// The . - /// The . - 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(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; - } - - /// - /// Determines if the specified is a handler. - /// - /// The . - /// true if the is a handler. Otherwise false. - /// - /// Override this method to provide custom logic to determine which methods are considered handlers. - /// - 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; - } } } diff --git a/src/Mvc/Mvc.RazorPages/src/ApplicationModels/IPageApplicationModelPartsProvider.cs b/src/Mvc/Mvc.RazorPages/src/ApplicationModels/IPageApplicationModelPartsProvider.cs new file mode 100644 index 0000000000..3d19f95029 --- /dev/null +++ b/src/Mvc/Mvc.RazorPages/src/ApplicationModels/IPageApplicationModelPartsProvider.cs @@ -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 +{ + /// + /// Provides parts that are used to construct a instance + /// + public interface IPageApplicationModelPartsProvider + { + /// + /// Creates a for the specified .s + /// + /// The . + /// The . + PageHandlerModel CreateHandlerModel(MethodInfo method); + + /// + /// Creates a for the specified . + /// + /// The . + /// The . + PageParameterModel CreateParameterModel(ParameterInfo parameter); + + /// + /// Creates a for the . + /// + /// The . + /// The . + PagePropertyModel CreatePropertyModel(PropertyInfo property); + + /// + /// Determines if the specified is a handler. + /// + /// The . + /// true if the is a handler. Otherwise false. + /// + /// Override this method to provide custom logic to determine which methods are considered handlers. + /// + bool IsHandler(MethodInfo methodInfo); + } +} diff --git a/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs index c152a9a54d..c17c80927a 100644 --- a/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs +++ b/src/Mvc/Mvc.RazorPages/src/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs @@ -113,6 +113,8 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddEnumerable( ServiceDescriptor.Singleton()); + services.TryAddSingleton(); + services.TryAddEnumerable( ServiceDescriptor.Singleton()); diff --git a/src/Mvc/Mvc.RazorPages/test/ApplicationModels/AuthorizationPageApplicationModelProviderTest.cs b/src/Mvc/Mvc.RazorPages/test/ApplicationModels/AuthorizationPageApplicationModelProviderTest.cs index 297c751bab..b2f17f48cf 100644 --- a/src/Mvc/Mvc.RazorPages/test/ApplicationModels/AuthorizationPageApplicationModelProviderTest.cs +++ b/src/Mvc/Mvc.RazorPages/test/ApplicationModels/AuthorizationPageApplicationModelProviderTest.cs @@ -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); diff --git a/src/Mvc/Mvc.RazorPages/test/ApplicationModels/DefaultPageApplicationModelProviderTest.cs b/src/Mvc/Mvc.RazorPages/test/ApplicationModels/DefaultPageApplicationModelProviderTest.cs index 83e4855da2..78aa991bd9 100644 --- a/src/Mvc/Mvc.RazorPages/test/ApplicationModels/DefaultPageApplicationModelProviderTest.cs +++ b/src/Mvc/Mvc.RazorPages/test/ApplicationModels/DefaultPageApplicationModelProviderTest.cs @@ -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)); } } } diff --git a/src/Mvc/Mvc.RazorPages/test/ApplicationModels/ResponseCacheFilterApplicationModelProviderTest.cs b/src/Mvc/Mvc.RazorPages/test/ApplicationModels/ResponseCacheFilterApplicationModelProviderTest.cs index e61666acf3..4c757bd1df 100644 --- a/src/Mvc/Mvc.RazorPages/test/ApplicationModels/ResponseCacheFilterApplicationModelProviderTest.cs +++ b/src/Mvc/Mvc.RazorPages/test/ApplicationModels/ResponseCacheFilterApplicationModelProviderTest.cs @@ -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);