diff options
author | David Fowler <davidfowl@gmail.com> | 2020-11-12 07:57:53 +0300 |
---|---|---|
committer | David Fowler <davidfowl@gmail.com> | 2020-11-12 07:57:53 +0300 |
commit | e9d16525cf3a832631a4e29ce826290adae873a9 (patch) | |
tree | 390d5e2bc9dc9728ae51ffad232fc5c9e686f1bb | |
parent | 15a8515724cf21046dfd40685fdc10240a628362 (diff) |
5 files changed, 82 insertions, 49 deletions
diff --git a/src/Mvc/Mvc.Core/src/Controllers/ControllerBinderDelegateProvider.cs b/src/Mvc/Mvc.Core/src/Controllers/ControllerBinderDelegateProvider.cs index a590b6b19d..33a7c8e12f 100644 --- a/src/Mvc/Mvc.Core/src/Controllers/ControllerBinderDelegateProvider.cs +++ b/src/Mvc/Mvc.Core/src/Controllers/ControllerBinderDelegateProvider.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -46,8 +46,8 @@ namespace Microsoft.AspNetCore.Mvc.Controllers var parameterBindingInfo = GetParameterBindingInfo( modelBinderFactory, modelMetadataProvider, - actionDescriptor, - mvcOptions); + actionDescriptor); + var propertyBindingInfo = GetPropertyBindingInfo(modelBinderFactory, modelMetadataProvider, actionDescriptor); if (parameterBindingInfo == null && propertyBindingInfo == null) @@ -55,9 +55,21 @@ namespace Microsoft.AspNetCore.Mvc.Controllers return null; } - return Bind; + if (propertyBindingInfo == null) + { + return async (controllerContext, controller, arguments) => + { + var (success, valueProvider) = await CompositeValueProvider.TryCreateAsync(controllerContext, controllerContext.ValueProviderFactories); + if (!success) + { + return; + } + + await BindArguments(valueProvider, controllerContext, arguments); + }; + } - async Task Bind(ControllerContext controllerContext, object controller, Dictionary<string, object> arguments) + return async (controllerContext, controller, arguments) => { var (success, valueProvider) = await CompositeValueProvider.TryCreateAsync(controllerContext, controllerContext.ValueProviderFactories); if (!success) @@ -65,6 +77,12 @@ namespace Microsoft.AspNetCore.Mvc.Controllers return; } + await BindArguments(valueProvider, controllerContext, arguments); + await BindProperties(valueProvider, controllerContext, controller, arguments); + }; + + async Task BindArguments(IValueProvider valueProvider, ControllerContext controllerContext, Dictionary<string, object> arguments) + { var parameters = actionDescriptor.Parameters; for (var i = 0; i < parameters.Count; i++) @@ -92,7 +110,10 @@ namespace Microsoft.AspNetCore.Mvc.Controllers arguments[parameter.Name] = result.Model; } } + } + async Task BindProperties(IValueProvider valueProvider, ControllerContext controllerContext, object controller, Dictionary<string, object> arguments) + { var properties = actionDescriptor.BoundProperties; for (var i = 0; i < properties.Count; i++) { @@ -125,8 +146,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers private static BinderItem[] GetParameterBindingInfo( IModelBinderFactory modelBinderFactory, IModelMetadataProvider modelMetadataProvider, - ControllerActionDescriptor actionDescriptor, - MvcOptions mvcOptions) + ControllerActionDescriptor actionDescriptor) { var parameters = actionDescriptor.Parameters; if (parameters.Count == 0) diff --git a/src/Mvc/Mvc.Core/src/Controllers/ControllerFactoryProvider.cs b/src/Mvc/Mvc.Core/src/Controllers/ControllerFactoryProvider.cs index 5c0ee05088..a75c9b9951 100644 --- a/src/Mvc/Mvc.Core/src/Controllers/ControllerFactoryProvider.cs +++ b/src/Mvc/Mvc.Core/src/Controllers/ControllerFactoryProvider.cs @@ -1,4 +1,4 @@ -// 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. using System; @@ -65,6 +65,12 @@ namespace Microsoft.AspNetCore.Mvc.Controllers var controllerActivator = _activatorProvider.CreateActivator(descriptor); var propertyActivators = GetPropertiesToActivate(descriptor); + + if (propertyActivators == null) + { + return controllerActivator; + } + object CreateController(ControllerContext controllerContext) { var controller = controllerActivator(controllerContext); @@ -106,14 +112,24 @@ namespace Microsoft.AspNetCore.Mvc.Controllers private Action<ControllerContext, object>[] GetPropertiesToActivate(ControllerActionDescriptor actionDescriptor) { - var propertyActivators = new Action<ControllerContext, object>[_propertyActivators.Length]; + List<Action<ControllerContext, object>> propertyActivators = null; + for (var i = 0; i < _propertyActivators.Length; i++) { var activatorProvider = _propertyActivators[i]; - propertyActivators[i] = activatorProvider.GetActivatorDelegate(actionDescriptor); + var activator = activatorProvider.GetActivatorDelegate(actionDescriptor); + if (activator != null) + { + if (propertyActivators == null) + { + propertyActivators = new List<Action<ControllerContext, object>>(_propertyActivators.Length); + } + + propertyActivators.Add(activator); + } } - return propertyActivators; + return propertyActivators?.ToArray(); } } } diff --git a/src/Mvc/Mvc.Core/src/Controllers/DefaultControllerPropertyActivator.cs b/src/Mvc/Mvc.Core/src/Controllers/DefaultControllerPropertyActivator.cs index 20f0b74ecc..5d848e3553 100644 --- a/src/Mvc/Mvc.Core/src/Controllers/DefaultControllerPropertyActivator.cs +++ b/src/Mvc/Mvc.Core/src/Controllers/DefaultControllerPropertyActivator.cs @@ -55,6 +55,12 @@ namespace Microsoft.AspNetCore.Mvc.Controllers } var propertiesToActivate = GetPropertiesToActivate(controllerType); + + if (propertiesToActivate.Length == 0) + { + return null; + } + void Activate(ControllerContext controllerContext, object controller) { for (var i = 0; i < propertiesToActivate.Length; i++) diff --git a/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerCache.cs b/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerCache.cs index 6be4771bb7..80472e9fbb 100644 --- a/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerCache.cs +++ b/src/Mvc/Mvc.Core/src/Infrastructure/ControllerActionInvokerCache.cs @@ -61,42 +61,34 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure } } - public ControllerActionInvokerCacheEntry GetCachedEntry(ControllerActionDescriptor actionDescriptor) + public ControllerActionInvokerCacheEntry CreateEntry(ControllerActionDescriptor actionDescriptor) { - var cache = CurrentCache; - - if (!cache.Entries.TryGetValue(actionDescriptor, out var cacheEntry)) - { - var parameterDefaultValues = ParameterDefaultValues - .GetParameterDefaultValues(actionDescriptor.MethodInfo); - - var objectMethodExecutor = ObjectMethodExecutor.Create( - actionDescriptor.MethodInfo, - actionDescriptor.ControllerTypeInfo, - parameterDefaultValues); - - var controllerFactory = _controllerFactoryProvider.CreateControllerFactory(actionDescriptor); - var controllerReleaser = _controllerFactoryProvider.CreateControllerReleaser(actionDescriptor); - var propertyBinderFactory = ControllerBinderDelegateProvider.CreateBinderDelegate( - _parameterBinder, - _modelBinderFactory, - _modelMetadataProvider, - actionDescriptor, - _mvcOptions); - - var actionMethodExecutor = ActionMethodExecutor.GetExecutor(objectMethodExecutor); - - cacheEntry = new ControllerActionInvokerCacheEntry( - Array.Empty<FilterItem>(), - controllerFactory, - controllerReleaser, - propertyBinderFactory, - objectMethodExecutor, - actionMethodExecutor); - cacheEntry = cache.Entries.GetOrAdd(actionDescriptor, cacheEntry); - } - - return cacheEntry; + var parameterDefaultValues = ParameterDefaultValues + .GetParameterDefaultValues(actionDescriptor.MethodInfo); + + var objectMethodExecutor = ObjectMethodExecutor.Create( + actionDescriptor.MethodInfo, + actionDescriptor.ControllerTypeInfo, + parameterDefaultValues); + + var controllerFactory = _controllerFactoryProvider.CreateControllerFactory(actionDescriptor); + var controllerReleaser = _controllerFactoryProvider.CreateControllerReleaser(actionDescriptor); + var propertyBinderFactory = ControllerBinderDelegateProvider.CreateBinderDelegate( + _parameterBinder, + _modelBinderFactory, + _modelMetadataProvider, + actionDescriptor, + _mvcOptions); + + var actionMethodExecutor = ActionMethodExecutor.GetExecutor(objectMethodExecutor); + + return new ControllerActionInvokerCacheEntry( + Array.Empty<FilterItem>(), + controllerFactory, + controllerReleaser, + propertyBinderFactory, + objectMethodExecutor, + actionMethodExecutor); } public (ControllerActionInvokerCacheEntry cacheEntry, IFilterMetadata[] filters) GetCachedResult(ControllerContext controllerContext) diff --git a/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs b/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs index 03bcd94deb..3d4cbf398d 100644 --- a/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs +++ b/src/Mvc/Mvc.Core/src/Routing/ControllerRequestDelegateFactory.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing // Super happy path (well assuming nobody cares about filters :O) if (actionDescriptor is ControllerActionDescriptor ca && ca.FilterDescriptors.Any(a => a.Filter is IApiBehaviorMetadata) && dataTokens == null) { - var entry = _controllerActionInvokerCache.GetCachedEntry(ca); + var entry = _controllerActionInvokerCache.CreateEntry(ca); return async context => { @@ -66,8 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing { Dictionary<string, object> arguments = null; - if (actionDescriptor.BoundProperties.Count > 0 || - actionDescriptor.Parameters.Count > 0) + if (entry.ControllerBinderDelegate != null) { // Allocation :( arguments = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); |