This commit is contained in:
Kiran Challa 2015-05-04 10:21:29 -07:00
parent fc87a436c1
commit f2e6c294b0
3 changed files with 49 additions and 36 deletions

View File

@ -31,23 +31,24 @@ namespace Microsoft.AspNet.Routing
} }
/// <summary> /// <summary>
/// Creates a <see cref="RouteValueDictionary"/> initialized with the provided input value. /// Creates a <see cref="RouteValueDictionary"/> initialized with the specified <paramref name="values"/>.
/// </summary> /// </summary>
/// <param name="obj">An object to initialize the dictionary. The value can be of type /// <param name="values">An object to initialize the dictionary. The value can be of type
/// <see cref="IDictionary{TKey, TValue}"/> or <see cref="IReadOnlyDictionary{TKey, TValue}"/> or /// <see cref="IDictionary{TKey, TValue}"/> or <see cref="IReadOnlyDictionary{TKey, TValue}"/>
/// any other object. /// or an object with public properties as key-value pairs.
/// </param> /// </param>
/// <remarks> /// <remarks>
/// If the value is a dictionary, then its entries are copied. Otherwise the object is interpreted as a set /// If the value is a dictionary or other <see cref="IEnumerable{KeyValuePair{string, object}}"/>,
/// of key-value-pairs where the property names are keys, and property values are the values, and copied /// then its entries are copied. Otherwise the object is interpreted as a set of key-value pairs where the
/// into the dictionary. Only public instance non-index properties are considered. /// property names are keys, and property values are the values, and copied into the dictionary.
/// Only public instance non-index properties are considered.
/// </remarks> /// </remarks>
public RouteValueDictionary(object obj) public RouteValueDictionary(object values)
: this() : this()
{ {
if (obj != null) if (values != null)
{ {
var keyValuePairCollection = obj as IEnumerable<KeyValuePair<string, object>>; var keyValuePairCollection = values as IEnumerable<KeyValuePair<string, object>>;
if (keyValuePairCollection != null) if (keyValuePairCollection != null)
{ {
foreach (var kvp in keyValuePairCollection) foreach (var kvp in keyValuePairCollection)
@ -57,7 +58,7 @@ namespace Microsoft.AspNet.Routing
return; return;
} }
var type = obj.GetType(); var type = values.GetType();
var allProperties = type.GetRuntimeProperties(); var allProperties = type.GetRuntimeProperties();
// This is done to support 'new' properties that hide a property on a base class // This is done to support 'new' properties that hide a property on a base class
@ -69,7 +70,7 @@ namespace Microsoft.AspNet.Routing
!property.GetMethod.IsStatic && !property.GetMethod.IsStatic &&
property.GetIndexParameters().Length == 0) property.GetIndexParameters().Length == 0)
{ {
var value = property.GetValue(obj); var value = property.GetValue(values);
if (ContainsKey(property.Name) && property.DeclaringType != type) if (ContainsKey(property.Name) && property.DeclaringType != type)
{ {
// This is a hidden property, ignore it. // This is a hidden property, ignore it.

View File

@ -414,7 +414,7 @@ namespace Microsoft.AspNet.Routing.Template
return string.Format( return string.Format(
"{{Accepted: '{0}' Filters: '{1}'}}", "{{Accepted: '{0}' Filters: '{1}'}}",
string.Join(", ", _acceptedValues.Keys), string.Join(", ", _acceptedValues.Keys),
string.Join(", ", _filters.Keys)); string.Join(", ", _filters?.Keys));
} }
} }

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNet.Testing; using Microsoft.AspNet.Testing;
using Xunit; using Xunit;
@ -168,36 +169,47 @@ namespace Microsoft.AspNet.Routing.Tests
expected); expected);
} }
[Fact] public static IEnumerable<object[]> IEnumerableKeyValuePairData
public void CreateFromReadOnlyDictionary_CopiesValues()
{ {
// Arrange get
var dictionary = new Dictionary<string, object>(); {
dictionary.Add("Name", "James"); var routeValues = new[]
dictionary.Add("Age", 30); {
var readonlyDictionary = (IReadOnlyDictionary<string, object>)dictionary; new KeyValuePair<string, object>("Name", "James"),
new KeyValuePair<string, object>("Age", 30),
new KeyValuePair<string, object>("Address", new Address() { City = "Redmond", State = "WA" })
};
// Act yield return new object[] { routeValues.ToDictionary(kvp => kvp.Key, kvp => kvp.Value) };
var dict = new RouteValueDictionary(readonlyDictionary);
// Assert yield return new object[] { routeValues.ToList() };
Assert.Equal(2, dict.Count);
Assert.Equal("James", dict["Name"]); yield return new object[] { routeValues };
Assert.Equal(30, dict["Age"]); }
} }
[Fact] [Theory]
public void CreateFromReadOnlyDictionary_ModifyRouteValueDictionary() [MemberData(nameof(IEnumerableKeyValuePairData))]
public void RouteValueDictionary_CopiesValues_FromIEnumerableKeyValuePair(object values)
{ {
// Arrange // Arrange & Act
var dictionary = new Dictionary<string, object>(); var dict = new RouteValueDictionary(values);
dictionary.Add("Name", "James");
dictionary.Add("Age", 30);
dictionary.Add("Address", new Address() { City = "Redmond", State = "WA" });
var readonlyDictionary = (IReadOnlyDictionary<string, object>)dictionary;
// Act // Assert
var routeValueDictionary = new RouteValueDictionary(readonlyDictionary); Assert.Equal(3, dict.Count);
Assert.Equal("James", dict["Name"]);
Assert.Equal(30, dict["Age"]);
var address = Assert.IsType<Address>(dict["Address"]);
Assert.Equal("Redmond", address.City);
Assert.Equal("WA", address.State);
}
[Theory]
[MemberData(nameof(IEnumerableKeyValuePairData))]
public void CreatedFrom_IEnumerableKeyValuePair_AllowsAddingOrModifyingValues(object values)
{
// Arrange & Act
var routeValueDictionary = new RouteValueDictionary(values);
routeValueDictionary.Add("City", "Redmond"); routeValueDictionary.Add("City", "Redmond");
// Assert // Assert