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:
parent
082f175b48
commit
0dadf56fc8
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -30,8 +30,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of
|
/// <param name="valueProviders">The sequence of <see cref="IValueProvider"/> to add to this instance of
|
||||||
/// <see cref="CompositeValueProvider"/>.</param>
|
/// <see cref="CompositeValueProvider"/>.</param>
|
||||||
public CompositeValueProvider(IEnumerable<IValueProvider> valueProviders)
|
protected CompositeValueProvider(IList<IValueProvider> valueProviders)
|
||||||
: base(valueProviders.ToList())
|
: base(valueProviders)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@ using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
public class FormValueProviderFactory : IValueProviderFactory
|
public class FormValueProviderFactory : IValueProviderFactory
|
||||||
{
|
{
|
||||||
public async Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
|
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
|
|
@ -18,23 +19,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = context.HttpContext.Request;
|
var request = context.HttpContext.Request;
|
||||||
|
|
||||||
if (request.HasFormContentType)
|
if (request.HasFormContentType)
|
||||||
{
|
{
|
||||||
var culture = GetCultureInfo(request);
|
return CreateValueProviderAsync(request);
|
||||||
|
|
||||||
return new ReadableStringCollectionValueProvider(
|
|
||||||
BindingSource.Form,
|
|
||||||
await request.ReadFormAsync(),
|
|
||||||
culture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,30 +8,35 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
public class JQueryFormValueProviderFactory : IValueProviderFactory
|
public class JQueryFormValueProviderFactory : IValueProviderFactory
|
||||||
{
|
{
|
||||||
public async Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
|
public Task<IValueProvider> GetValueProviderAsync(ValueProviderFactoryContext context)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = context.HttpContext.Request;
|
var request = context.HttpContext.Request;
|
||||||
|
|
||||||
if (request.HasFormContentType)
|
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,
|
BindingSource.Form,
|
||||||
await GetValueCollectionAsync(request),
|
await GetValueCollectionAsync(request),
|
||||||
CultureInfo.CurrentCulture);
|
CultureInfo.CurrentCulture);
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<IDictionary<string, StringValues>> GetValueCollectionAsync(HttpRequest request)
|
private static async Task<IDictionary<string, StringValues>> GetValueCollectionAsync(HttpRequest request)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
new JQueryFormValueProvider(bindingSource, new Dictionary<string, StringValues>(), culture);
|
new JQueryFormValueProvider(bindingSource, new Dictionary<string, StringValues>(), culture);
|
||||||
var valueProvider = new JQueryFormValueProvider(bindingSource, values, culture);
|
var valueProvider = new JQueryFormValueProvider(bindingSource, values, culture);
|
||||||
|
|
||||||
return new CompositeValueProvider(new[] { emptyValueProvider, valueProvider });
|
return new CompositeValueProvider() { emptyValueProvider, valueProvider };
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DNX451
|
#if DNX451
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
provider2.Setup(p => p.GetKeysFromPrefix("prefix"))
|
provider2.Setup(p => p.GetKeysFromPrefix("prefix"))
|
||||||
.Returns(dictionary)
|
.Returns(dictionary)
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var provider = new CompositeValueProvider(new[] { provider1, provider2.Object });
|
var provider = new CompositeValueProvider() { provider1, provider2.Object };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var values = provider.GetKeysFromPrefix("prefix");
|
var values = provider.GetKeysFromPrefix("prefix");
|
||||||
|
|
@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider1 = Mock.Of<IValueProvider>();
|
var provider1 = Mock.Of<IValueProvider>();
|
||||||
var provider2 = Mock.Of<IValueProvider>();
|
var provider2 = Mock.Of<IValueProvider>();
|
||||||
var provider = new CompositeValueProvider(new[] { provider1, provider2 });
|
var provider = new CompositeValueProvider() { provider1, provider2 };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var values = provider.GetKeysFromPrefix("prefix");
|
var values = provider.GetKeysFromPrefix("prefix");
|
||||||
|
|
@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var valueProvider1 = GetMockValueProvider("Test");
|
var valueProvider1 = GetMockValueProvider("Test");
|
||||||
var valueProvider2 = GetMockValueProvider("Unrelated");
|
var valueProvider2 = GetMockValueProvider("Unrelated");
|
||||||
|
|
||||||
var provider = new CompositeValueProvider(new List<IValueProvider>() { valueProvider1.Object, valueProvider2.Object });
|
var provider = new CompositeValueProvider() { valueProvider1.Object, valueProvider2.Object };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = provider.Filter(metadata.BindingSource);
|
var result = provider.Filter(metadata.BindingSource);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue