Introduce FormValueProviderFactory to expose form data as a value provider
This commit is contained in:
parent
04c7b50726
commit
d920003194
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class FormValueProviderFactory : IValueProviderFactory
|
||||
{
|
||||
private const string FormEncodedContentType = "application/x-www-form-urlencoded";
|
||||
|
||||
public async Task<IValueProvider> GetValueProviderAsync(RequestContext requestContext)
|
||||
{
|
||||
var request = requestContext.HttpContext.Request;
|
||||
|
||||
if (IsSupportedContentType(request))
|
||||
{
|
||||
var queryCollection = await request.GetFormAsync();
|
||||
var culture = GetCultureInfo(request);
|
||||
return new ReadableStringCollectionValueProvider(queryCollection, culture);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsSupportedContentType(HttpRequest request)
|
||||
{
|
||||
var contentType = request.Headers["Content-Type"];
|
||||
return !String.IsNullOrEmpty(contentType) &&
|
||||
contentType.Equals(FormEncodedContentType, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static CultureInfo GetCultureInfo(HttpRequest request)
|
||||
{
|
||||
// TODO: Tracked via https://github.com/aspnet/HttpAbstractions/issues/10. Determine what's the right way to
|
||||
// map Accept-Language to culture.
|
||||
return CultureInfo.CurrentCulture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public interface IValueProviderFactory
|
||||
|
|
@ -8,6 +9,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
/// <param name="requestContext">RequestContext that value provider will populate from</param>
|
||||
/// <returns>a value provider instance or null</returns>
|
||||
IValueProvider GetValueProvider(RequestContext requestContext);
|
||||
Task<IValueProvider> GetValueProviderAsync(RequestContext requestContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
using System.Globalization;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class QueryStringValueProvider : NameValuePairsValueProvider
|
||||
{
|
||||
public QueryStringValueProvider(HttpContext context, CultureInfo culture)
|
||||
: base(context.Request.Query, culture)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
|
|
@ -8,24 +8,28 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
private static readonly object _cacheKey = new object();
|
||||
|
||||
public IValueProvider GetValueProvider(RequestContext requestContext)
|
||||
public Task<IValueProvider> GetValueProviderAsync(RequestContext requestContext)
|
||||
{
|
||||
if (requestContext == null)
|
||||
{
|
||||
throw Error.ArgumentNull("requestContext");
|
||||
}
|
||||
|
||||
// Process the query string once-per request.
|
||||
IDictionary<object, object> storage = requestContext.HttpContext.Items;
|
||||
// Process the query collection once-per request.
|
||||
var storage = requestContext.HttpContext.Items;
|
||||
object value;
|
||||
IValueProvider provider;
|
||||
if (!storage.TryGetValue(_cacheKey, out value))
|
||||
{
|
||||
var provider = new QueryStringValueProvider(requestContext.HttpContext, CultureInfo.InvariantCulture);
|
||||
var queryCollection = requestContext.HttpContext.Request.Query;
|
||||
provider = new ReadableStringCollectionValueProvider(queryCollection, CultureInfo.InvariantCulture);
|
||||
storage[_cacheKey] = provider;
|
||||
return provider;
|
||||
}
|
||||
|
||||
return (QueryStringValueProvider)value;
|
||||
else
|
||||
{
|
||||
provider = (ReadableStringCollectionValueProvider)value;
|
||||
}
|
||||
return Task.FromResult(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class NameValuePairsValueProvider : IEnumerableValueProvider
|
||||
public class ReadableStringCollectionValueProvider : IEnumerableValueProvider
|
||||
{
|
||||
private readonly CultureInfo _culture;
|
||||
private PrefixContainer _prefixContainer;
|
||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
/// <param name="values">The key value pairs to wrap.</param>
|
||||
/// <param name="culture">The culture to return with ValueProviderResult instances.</param>
|
||||
public NameValuePairsValueProvider(IReadableStringCollection values, CultureInfo culture)
|
||||
public ReadableStringCollectionValueProvider(IReadableStringCollection values, CultureInfo culture)
|
||||
{
|
||||
if (values == null)
|
||||
{
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class RouteValueValueProviderFactory : IValueProviderFactory
|
||||
{
|
||||
public IValueProvider GetValueProvider(RequestContext requestContext)
|
||||
public Task<IValueProvider> GetValueProviderAsync(RequestContext requestContext)
|
||||
{
|
||||
return new DictionaryBasedValueProvider(requestContext.RouteValues);
|
||||
var valueProvider = new DictionaryBasedValueProvider(requestContext.RouteValues);
|
||||
return Task.FromResult<IValueProvider>(valueProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
@ -16,7 +17,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
_valueProviderFactory = valueProviderFactories;
|
||||
}
|
||||
|
||||
public ActionDescriptor Select(RequestContext context)
|
||||
public async Task<ActionDescriptor> SelectAsync(RequestContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
|
|
@ -36,7 +37,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
else
|
||||
{
|
||||
return SelectBestCandidate(context, matching);
|
||||
return await SelectBestCandidate(context, matching);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,9 +53,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
(descriptor.DynamicConstraints == null || descriptor.DynamicConstraints.All(c => c.Accept(context)));
|
||||
}
|
||||
|
||||
protected virtual ActionDescriptor SelectBestCandidate(RequestContext context, List<ActionDescriptor> candidates)
|
||||
protected virtual async Task<ActionDescriptor> SelectBestCandidate(RequestContext context, List<ActionDescriptor> candidates)
|
||||
{
|
||||
var valueProviders = _valueProviderFactory.Select(vpf => vpf.GetValueProvider(context)).ToArray();
|
||||
var valueProviders = await Task.WhenAll(_valueProviderFactory.Select(vpf => vpf.GetValueProviderAsync(context)));
|
||||
valueProviders = valueProviders.Where(vp => vp != null).ToArray();
|
||||
|
||||
var applicableCandiates = new List<ActionDescriptorCandidate>();
|
||||
foreach (var action in candidates)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IActionSelector
|
||||
{
|
||||
ActionDescriptor Select(RequestContext context);
|
||||
Task<ActionDescriptor> SelectAsync(RequestContext context);
|
||||
|
||||
bool Match(ActionDescriptor descriptor, RequestContext context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
var routeValues = context.GetFeature<IRouteValues>();
|
||||
var requestContext = new RequestContext(context, routeValues.Values);
|
||||
|
||||
var actionDescriptor = ActionSelector.Select(requestContext);
|
||||
var actionDescriptor = await ActionSelector.SelectAsync(requestContext);
|
||||
|
||||
if (actionDescriptor == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||
{
|
||||
public class FormValueProviderFactoryTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetValueProvider_ReturnsNull_WhenContentTypeIsNotFormUrlEncoded()
|
||||
{
|
||||
// Arrange
|
||||
var requestContext = CreateRequestContext("some-content-type");
|
||||
var factory = new FormValueProviderFactory();
|
||||
|
||||
// Act
|
||||
var result = await factory.GetValueProviderAsync(requestContext);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetValueProvider_ReturnsValueProviderInstaceWithInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var requestContext = CreateRequestContext("application/x-www-form-urlencoded");
|
||||
var factory = new FormValueProviderFactory();
|
||||
|
||||
// Act
|
||||
var result = await factory.GetValueProviderAsync(requestContext);
|
||||
|
||||
// Assert
|
||||
var valueProvider = Assert.IsType<ReadableStringCollectionValueProvider>(result);
|
||||
Assert.Equal(CultureInfo.CurrentCulture, valueProvider.Culture);
|
||||
}
|
||||
|
||||
private static RequestContext CreateRequestContext(string contentType)
|
||||
{
|
||||
var collection = Mock.Of<IReadableStringCollection>();
|
||||
var request = new Mock<HttpRequest>();
|
||||
request.Setup(f => f.GetFormAsync()).Returns(Task.FromResult(collection));
|
||||
|
||||
var mockHeader = new Mock<IHeaderDictionary>();
|
||||
mockHeader.Setup(h => h["Content-Type"]).Returns(contentType);
|
||||
request.SetupGet(r => r.Headers).Returns(mockHeader.Object);
|
||||
|
||||
var context = new Mock<HttpContext>();
|
||||
context.SetupGet(c => c.Request).Returns(request.Object);
|
||||
|
||||
var requestContext = new RequestContext(context.Object, new Dictionary<string, object>());
|
||||
return requestContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -14,11 +15,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetValueProvider_WhenrequestContextParameterIsNull_Throws()
|
||||
{
|
||||
// Act and Assert
|
||||
ExceptionAssert.ThrowsArgumentNull(() => _factory.GetValueProvider(requestContext: null), "requestContext");
|
||||
ExceptionAssert.ThrowsArgumentNull(() => _factory.GetValueProviderAsync(requestContext: null), "requestContext");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetValueProvider_ReturnsQueryStringValueProviderInstaceWithInvariantCulture()
|
||||
public async Task GetValueProvider_ReturnsQueryStringValueProviderInstaceWithInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var request = new Mock<HttpRequest>();
|
||||
|
|
@ -29,10 +30,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
var requestContext = new RequestContext(context.Object, new Dictionary<string, object>());
|
||||
|
||||
// Act
|
||||
IValueProvider result = _factory.GetValueProvider(requestContext);
|
||||
var result = await _factory.GetValueProviderAsync(requestContext);
|
||||
|
||||
// Assert
|
||||
var valueProvider = Assert.IsType<QueryStringValueProvider>(result);
|
||||
var valueProvider = Assert.IsType<ReadableStringCollectionValueProvider>(result);
|
||||
Assert.Equal(CultureInfo.InvariantCulture, valueProvider.Culture);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||
{
|
||||
public class NameValuePairsValueProviderTest
|
||||
public class ReadableStringCollectionValueProviderTest
|
||||
{
|
||||
private static readonly IReadableStringCollection _backingStore = new ReadableStringCollection(
|
||||
new Dictionary<string, string[]>
|
||||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
// Act & assert
|
||||
ExceptionAssert.ThrowsArgumentNull(
|
||||
() => new NameValuePairsValueProvider(values: null, culture: CultureInfo.InvariantCulture),
|
||||
() => new ReadableStringCollectionValueProvider(values: null, culture: CultureInfo.InvariantCulture),
|
||||
"values");
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void ContainsPrefix_GuardClauses()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act & assert
|
||||
ExceptionAssert.ThrowsArgumentNull(
|
||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
// Arrange
|
||||
var backingStore = new ReadableStringCollection(new Dictionary<string, string[]>());
|
||||
var valueProvider = new NameValuePairsValueProvider(backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(backingStore, null);
|
||||
|
||||
// Act
|
||||
bool result = valueProvider.ContainsPrefix("");
|
||||
|
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void ContainsPrefix_WithNonEmptyCollection_ReturnsTrueForEmptyPrefix()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act
|
||||
bool result = valueProvider.ContainsPrefix("");
|
||||
|
|
@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void ContainsPrefix_WithNonEmptyCollection_ReturnsTrueForKnownPrefixes()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act & Assert
|
||||
Assert.True(valueProvider.ContainsPrefix("foo"));
|
||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void ContainsPrefix_WithNonEmptyCollection_ReturnsFalseForUnknownPrefix()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act
|
||||
bool result = valueProvider.ContainsPrefix("biff");
|
||||
|
|
@ -95,7 +95,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetKeysFromPrefix_GuardClauses()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act & assert
|
||||
ExceptionAssert.ThrowsArgumentNull(
|
||||
|
|
@ -107,7 +107,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetKeysFromPrefix_EmptyPrefix_ReturnsAllPrefixes()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act
|
||||
IDictionary<string, string> result = valueProvider.GetKeysFromPrefix("");
|
||||
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetKeysFromPrefix_UnknownPrefix_ReturnsEmptyDictionary()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act
|
||||
IDictionary<string, string> result = valueProvider.GetKeysFromPrefix("abc");
|
||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetKeysFromPrefix_KnownPrefix_ReturnsMatchingItems()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act
|
||||
IDictionary<string, string> result = valueProvider.GetKeysFromPrefix("bar");
|
||||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetValue_GuardClauses()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act & assert
|
||||
ExceptionAssert.ThrowsArgumentNull(
|
||||
|
|
@ -163,7 +163,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
// Arrange
|
||||
var culture = CultureInfo.GetCultureInfo("fr-FR");
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, culture);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, culture);
|
||||
|
||||
// Act
|
||||
ValueProviderResult vpResult = valueProvider.GetValue("bar.baz");
|
||||
|
|
@ -180,7 +180,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
// Arrange
|
||||
var culture = CultureInfo.GetCultureInfo("fr-FR");
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, culture);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, culture);
|
||||
|
||||
// Act
|
||||
ValueProviderResult vpResult = valueProvider.GetValue("foo");
|
||||
|
|
@ -201,7 +201,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
//{
|
||||
// // Arrange
|
||||
// var culture = CultureInfo.GetCultureInfo("fr-FR");
|
||||
// var valueProvider = new NameValuePairsValueProvider(_backingStore, culture);
|
||||
// var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, culture);
|
||||
|
||||
// // Act
|
||||
// ValueProviderResult vpResult = valueProvider.GetValue(key);
|
||||
|
|
@ -223,7 +223,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{ "key", new string[] { null, null, "value" } }
|
||||
});
|
||||
var culture = CultureInfo.GetCultureInfo("fr-FR");
|
||||
var valueProvider = new NameValuePairsValueProvider(backingStore, culture);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(backingStore, culture);
|
||||
|
||||
// Act
|
||||
ValueProviderResult vpResult = valueProvider.GetValue("key");
|
||||
|
|
@ -237,7 +237,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public void GetValue_ReturnsNullIfKeyNotFound()
|
||||
{
|
||||
// Arrange
|
||||
var valueProvider = new NameValuePairsValueProvider(_backingStore, null);
|
||||
var valueProvider = new ReadableStringCollectionValueProvider(_backingStore, null);
|
||||
|
||||
// Act
|
||||
ValueProviderResult vpResult = valueProvider.GetValue("bar");
|
||||
Loading…
Reference in New Issue