diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateEntry.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateEntry.cs index 0b8bd32d4b..a4f6391bbc 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateEntry.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelStateEntry.cs @@ -10,6 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// public abstract class ModelStateEntry { + private ModelErrorCollection _errors; /// /// Gets the raw value from the request associated with this entry. /// @@ -23,7 +24,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding /// /// Gets the for this entry. /// - public ModelErrorCollection Errors { get; } = new ModelErrorCollection(); + public ModelErrorCollection Errors + { + get + { + if (_errors == null) + { + _errors = new ModelErrorCollection(); + } + return _errors; + } + } /// /// Gets or sets the for this entry. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultCollectionValidationStrategy.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultCollectionValidationStrategy.cs index fd9f02d49b..3823c8ac20 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultCollectionValidationStrategy.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/DefaultCollectionValidationStrategy.cs @@ -1,11 +1,14 @@ // 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; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; +using System.Linq.Expressions; namespace Microsoft.AspNetCore.Mvc.Internal { @@ -44,7 +47,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal /// /// Gets an instance of . /// - public static readonly IValidationStrategy Instance = new DefaultCollectionValidationStrategy(); + public static readonly DefaultCollectionValidationStrategy Instance = new DefaultCollectionValidationStrategy(); + private readonly ConcurrentDictionary> _genericGetEnumeratorCache = new ConcurrentDictionary>(); private DefaultCollectionValidationStrategy() { @@ -60,10 +64,21 @@ namespace Microsoft.AspNetCore.Mvc.Internal return new Enumerator(metadata.ElementMetadata, key, enumerator); } - public static IEnumerator GetEnumeratorForElementType(ModelMetadata metadata, object model) + public IEnumerator GetEnumeratorForElementType(ModelMetadata metadata, object model) { - var getEnumeratorMethod = _getEnumerator.MakeGenericMethod(metadata.ElementType); - return (IEnumerator)getEnumeratorMethod.Invoke(null, new object[] { model }); + Func getEnumerator = _genericGetEnumeratorCache.GetOrAdd( + key: metadata.ElementType, + valueFactory: (type) => { + var getEnumeratorMethod = _getEnumerator.MakeGenericMethod(type); + var parameter = Expression.Parameter(typeof(object), "model"); + var expression = + Expression.Lambda>( + Expression.Call(null, getEnumeratorMethod, parameter), + parameter); + return expression.Compile(); + }); + + return getEnumerator(model); } // Called via reflection. diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ExplicitIndexCollectionValidationStrategy.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ExplicitIndexCollectionValidationStrategy.cs index 16f57ebc8f..f4f940f8ae 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ExplicitIndexCollectionValidationStrategy.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ExplicitIndexCollectionValidationStrategy.cs @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal string key, object model) { - var enumerator = DefaultCollectionValidationStrategy.GetEnumeratorForElementType(metadata, model); + var enumerator = DefaultCollectionValidationStrategy.Instance.GetEnumeratorForElementType(metadata, model); return new Enumerator(metadata.ElementMetadata, key, ElementKeys, enumerator); }