Skip to content

Commit

Permalink
Adding a context class for ValueProviderFactories
Browse files Browse the repository at this point in the history
This allows model binding to once again be independent of routing. Sending
RouteContext into model binding was an odd choice from a layering
point-of-view.
  • Loading branch information
rynowak committed Jun 12, 2014
1 parent 44ed23f commit 7f34c94
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ public DefaultActionBindingContextProvider(IModelMetadataProvider modelMetadataP

public Task<ActionBindingContext> GetActionBindingContextAsync(ActionContext actionContext)
{
var routeContext = new RouteContext(actionContext.HttpContext);
routeContext.RouteData = actionContext.RouteData;
var valueProviders = _valueProviderFactories.Select(factory => factory.GetValueProvider(routeContext))
var factoryContext = new ValueProviderFactoryContext(
actionContext.HttpContext,
actionContext.RouteData.Values);

var valueProviders = _valueProviderFactories.Select(factory => factory.GetValueProvider(factoryContext))
.Where(vp => vp != null);
var context = new ActionBindingContext(
actionContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
<Compile Include="ValueProviders\QueryStringValueProviderFactory.cs" />
<Compile Include="ValueProviders\ReadableStringCollectionValueProvider.cs" />
<Compile Include="ValueProviders\RouteValueValueProviderFactory.cs" />
<Compile Include="ValueProviders\ValueProviderFactoryContext.cs" />
<Compile Include="ValueProviders\ValueProviderResult.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
using System;
using System.Globalization;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;

namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class FormValueProviderFactory : IValueProviderFactory
{
private const string FormEncodedContentType = "application/x-www-form-urlencoded";

public IValueProvider GetValueProvider([NotNull] RouteContext routeContext)
public IValueProvider GetValueProvider([NotNull] ValueProviderFactoryContext context)
{
var request = routeContext.HttpContext.Request;
var request = context.HttpContext.Request;

if (IsSupportedContentType(request))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNet.Routing;

namespace Microsoft.AspNet.Mvc.ModelBinding
{
public interface IValueProviderFactory
{
/// <summary>
/// Get a value provider with values from the given <paramref name="requestContext"/>.
/// </summary>
/// <param name="routeContext">RouteContext that value provider will populate from</param>
/// <param name="context">ValueProviderFactoryContext that value provider will populate from</param>
/// <returns>a value provider instance or null</returns>
IValueProvider GetValueProvider([NotNull] RouteContext routeContext);
IValueProvider GetValueProvider([NotNull] ValueProviderFactoryContext context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,22 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Globalization;
using Microsoft.AspNet.Routing;

namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class QueryStringValueProviderFactory : IValueProviderFactory
{
private static readonly object _cacheKey = new object();

public IValueProvider GetValueProvider([NotNull] RouteContext routeContext)
public IValueProvider GetValueProvider([NotNull] ValueProviderFactoryContext context)
{
// Process the query collection once-per request.
var storage = routeContext.HttpContext.Items;
var storage = context.HttpContext.Items;
object value;
IValueProvider provider;
if (!storage.TryGetValue(_cacheKey, out value))
{
var queryCollection = routeContext.HttpContext.Request.Query;
var queryCollection = context.HttpContext.Request.Query;
provider = new ReadableStringCollectionValueProvider(queryCollection, CultureInfo.InvariantCulture);
storage[_cacheKey] = provider;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNet.Routing;

namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class RouteValueValueProviderFactory : IValueProviderFactory
{
public IValueProvider GetValueProvider([NotNull] RouteContext routeContext)
public IValueProvider GetValueProvider([NotNull] ValueProviderFactoryContext context)
{
return new DictionaryBasedValueProvider(routeContext.RouteData.Values);
return new DictionaryBasedValueProvider(context.RouteValues);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using Microsoft.AspNet.Http;

namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class ValueProviderFactoryContext
{
public ValueProviderFactoryContext(
[NotNull] HttpContext httpContext,
[NotNull] IDictionary<string, object> routeValues)
{
HttpContext = httpContext;
RouteValues = routeValues;
}

public HttpContext HttpContext { get; private set; }

public IDictionary<string, object> RouteValues { get; private set; }
}
}
1 change: 0 additions & 1 deletion src/Microsoft.AspNet.Mvc.ModelBinding/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"dependencies": {
"Microsoft.AspNet.Http": "0.1-alpha-*",
"Microsoft.AspNet.Mvc.Common": "",
"Microsoft.AspNet.Routing": "0.1-alpha-*",
"Microsoft.DataAnnotations": "0.1-alpha-*",
"Microsoft.Framework.DependencyInjection": "0.1-alpha-*",
"Newtonsoft.Json": "5.0.8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public class FormValueProviderFactoryTests
public void GetValueProvider_ReturnsNull_WhenContentTypeIsNotFormUrlEncoded()
{
// Arrange
var requestContext = CreateRequestContext("some-content-type");
var context = CreateContext("some-content-type");
var factory = new FormValueProviderFactory();

// Act
var result = factory.GetValueProvider(requestContext);
var result = factory.GetValueProvider(context);

// Assert
Assert.Null(result);
Expand All @@ -35,18 +35,18 @@ public void GetValueProvider_ReturnsNull_WhenContentTypeIsNotFormUrlEncoded()
public void GetValueProvider_ReturnsValueProviderInstaceWithInvariantCulture(string contentType)
{
// Arrange
var requestContext = CreateRequestContext(contentType);
var context = CreateContext(contentType);
var factory = new FormValueProviderFactory();

// Act
var result = factory.GetValueProvider(requestContext);
var result = factory.GetValueProvider(context);

// Assert
var valueProvider = Assert.IsType<ReadableStringCollectionValueProvider>(result);
Assert.Equal(CultureInfo.CurrentCulture, valueProvider.Culture);
}

private static RouteContext CreateRequestContext(string contentType)
private static ValueProviderFactoryContext CreateContext(string contentType)
{
var collection = Mock.Of<IReadableStringCollection>();
var request = new Mock<HttpRequest>();
Expand All @@ -59,9 +59,9 @@ private static RouteContext CreateRequestContext(string contentType)
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Request).Returns(request.Object);

var routeContext = new RouteContext(context.Object);
routeContext.RouteData.Values = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
return routeContext;
return new ValueProviderFactoryContext(
context.Object,
new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ public void GetValueProvider_ReturnsQueryStringValueProviderInstaceWithInvariant
var context = new Mock<HttpContext>();
context.SetupGet(c => c.Items).Returns(new Dictionary<object, object>());
context.SetupGet(c => c.Request).Returns(request.Object);
var routeContext = new RouteContext(context.Object);
routeContext.RouteData.Values = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
var factoryContext = new ValueProviderFactoryContext(context.Object, new Dictionary<String, object>(StringComparer.OrdinalIgnoreCase));

// Act
var result = _factory.GetValueProvider(routeContext);
var result = _factory.GetValueProvider(factoryContext);

// Assert
var valueProvider = Assert.IsType<ReadableStringCollectionValueProvider>(result);
Expand Down

0 comments on commit 7f34c94

Please sign in to comment.