From 45a72a0e18feb8ea368fc14ed790a787edc8bde9 Mon Sep 17 00:00:00 2001 From: mnltejaswini Date: Wed, 9 Mar 2016 10:50:42 -0800 Subject: [PATCH] [Perf] Optimize creation of VDD Fixes #3906 --- .../RazorPageActivator.cs | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageActivator.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageActivator.cs index 5ed5746211..4000df8184 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageActivator.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageActivator.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Concurrent; +using System.Diagnostics; using System.Reflection; +using System.Linq.Expressions; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.Rendering; @@ -17,6 +19,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor /// public class RazorPageActivator : IRazorPageActivator { + private delegate ViewDataDictionary CreateViewDataNested(ViewDataDictionary source); + private delegate ViewDataDictionary CreateViewDataRoot( + IModelMetadataProvider metadataProvider, + ModelStateDictionary modelState); + // Name of the "public TModel Model" property on RazorPage private const string ModelPropertyName = "Model"; private readonly ConcurrentDictionary _activationInfo; @@ -63,17 +70,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor if (context.ViewData == null) { // Create ViewDataDictionary(IModelMetadataProvider, ModelStateDictionary). - return (ViewDataDictionary)Activator.CreateInstance( - activationInfo.ViewDataDictionaryType, + return activationInfo.CreateViewDataRoot( _metadataProvider, context.ModelState); } else if (context.ViewData.GetType() != activationInfo.ViewDataDictionaryType) { // Create ViewDataDictionary(ViewDataDictionary). - return (ViewDataDictionary)Activator.CreateInstance( - activationInfo.ViewDataDictionaryType, - context.ViewData); + return activationInfo.CreateViewDataNested(context.ViewData); } return context.ViewData; @@ -96,6 +100,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor return new PageActivationInfo { ViewDataDictionaryType = viewDataType, + CreateViewDataNested = GetCreateViewDataNested(viewDataType), + CreateViewDataRoot = GetCreateViewDataRoot(viewDataType), PropertyActivators = PropertyActivator.GetPropertiesToActivate( type, typeof(RazorInjectAttribute), @@ -104,6 +110,41 @@ namespace Microsoft.AspNetCore.Mvc.Razor }; } + private CreateViewDataNested GetCreateViewDataNested(Type viewDataDictionaryType) + { + var parameterTypes = new Type[] { typeof(ViewDataDictionary) }; + var matchingConstructor = viewDataDictionaryType.GetConstructor(parameterTypes); + Debug.Assert(matchingConstructor != null); + + var parameters = new ParameterExpression[] { Expression.Parameter(parameterTypes[0]) }; + var newExpression = Expression.New(matchingConstructor, parameters); + var castNewCall = Expression.Convert( + newExpression, + typeof(ViewDataDictionary)); + var lambda = Expression.Lambda(castNewCall, parameters); + return lambda.Compile(); + } + + private CreateViewDataRoot GetCreateViewDataRoot(Type viewDataDictionaryType) + { + var parameterTypes = new Type[] { + typeof(IModelMetadataProvider), + typeof(ModelStateDictionary) }; + var matchingConstructor = viewDataDictionaryType.GetConstructor(parameterTypes); + Debug.Assert(matchingConstructor != null); + + var parameters = new ParameterExpression[] { + Expression.Parameter(parameterTypes[0]), + Expression.Parameter(parameterTypes[1]) }; + var newExpression = Expression.New(matchingConstructor, parameters); + var castNewCall = Expression.Convert( + newExpression, + typeof(ViewDataDictionary)); + var lambda = Expression.Lambda(castNewCall, parameters); + return lambda.Compile(); + } + + private PropertyActivator CreateActivateInfo(PropertyInfo property) { Func valueAccessor; @@ -147,6 +188,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor public Type ViewDataDictionaryType { get; set; } + public CreateViewDataNested CreateViewDataNested { get; set; } + + public CreateViewDataRoot CreateViewDataRoot { get; set; } + public Action ViewDataDictionarySetter { get; set; } } }