Reducing allocations in value providers

- Don't go async in formdata providers unless we need to
- Remove unnecessary defensive copy in CompositeValueProvider
This commit is contained in:
Ryan Nowak 2015-10-05 21:28:01 -07:00
parent 082f175b48
commit 0dadf56fc8
5 changed files with 45 additions and 24 deletions

View File

@ -0,0 +1,18 @@
// 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.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.Internal
{
public static class TaskCache<T>
{
private static readonly Task<T> _defaultCompletedTask = Task.FromResult(default(T));
/// <summary>
/// Gets a completed <see cref="Task"/> with the value of <c>default(T)</c>.
/// </summary>
public static Task<T> DefaultCompletedTask => _defaultCompletedTask;
}
}

View File

@ -30,8 +30,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
/// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of
/// <see cref="CompositeValueProvider"/>.</param>
public CompositeValueProvider(IEnumerable<IValueProvider> valueProviders)
: base(valueProviders.ToList())
protected CompositeValueProvider(IList<IValueProvider> valueProviders)
: base(valueProviders)
{
}

View File

@ -5,12 +5,13 @@ using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class FormValueProviderFactory : IValueProviderFactory
{
public async Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
@ -18,23 +19,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
var request = context.HttpContext.Request;
if (request.HasFormContentType)
{
var culture = GetCultureInfo(request);
return new ReadableStringCollectionValueProvider(
BindingSource.Form,
await request.ReadFormAsync(),
culture);
return CreateValueProviderAsync(request);
}
return null;
return TaskCache<IValueProvider>.DefaultCompletedTask;
}
private static CultureInfo GetCultureInfo(HttpRequest request)
private static async Task<IValueProvider> CreateValueProviderAsync(HttpRequest request)
{
return CultureInfo.CurrentCulture;
return new ReadableStringCollectionValueProvider(
BindingSource.Form,
await request.ReadFormAsync(),
CultureInfo.CurrentCulture);
}
}
}

View File

@ -8,30 +8,35 @@ using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class JQueryFormValueProviderFactory : IValueProviderFactory
{
public async Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var request = context.HttpContext.Request;
if (request.HasFormContentType)
{
return new JQueryFormValueProvider(
return CreateValueProviderAsync(request);
}
return TaskCache<IValueProvider>.DefaultCompletedTask;
}
private static async Task<IValueProvider> CreateValueProviderAsync(HttpRequest request)
{
return new JQueryFormValueProvider(
BindingSource.Form,
await GetValueCollectionAsync(request),
CultureInfo.CurrentCulture);
}
return null;
}
private static async Task<IDictionary<string, StringValues>> GetValueCollectionAsync(HttpRequest request)

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
new JQueryFormValueProvider(bindingSource, new Dictionary<string, StringValues>(), culture);
var valueProvider = new JQueryFormValueProvider(bindingSource, values, culture);
return new CompositeValueProvider(new[] { emptyValueProvider, valueProvider });
return new CompositeValueProvider() { emptyValueProvider, valueProvider };
}
#if DNX451
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
provider2.Setup(p => p.GetKeysFromPrefix("prefix"))
.Returns(dictionary)
.Verifiable();
var provider = new CompositeValueProvider(new[] { provider1, provider2.Object });
var provider = new CompositeValueProvider() { provider1, provider2.Object };
// Act
var values = provider.GetKeysFromPrefix("prefix");
@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// Arrange
var provider1 = Mock.Of<IValueProvider>();
var provider2 = Mock.Of<IValueProvider>();
var provider = new CompositeValueProvider(new[] { provider1, provider2 });
var provider = new CompositeValueProvider() { provider1, provider2 };
// Act
var values = provider.GetKeysFromPrefix("prefix");
@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var valueProvider1 = GetMockValueProvider("Test");
var valueProvider2 = GetMockValueProvider("Unrelated");
var provider = new CompositeValueProvider(new List<IValueProvider>() { valueProvider1.Object, valueProvider2.Object });
var provider = new CompositeValueProvider() { valueProvider1.Object, valueProvider2.Object };
// Act
var result = provider.Filter(metadata.BindingSource);