Fix RouteValueDictionary to handle read-only dictionaries.

This commit is contained in:
Kiran Challa 2015-05-01 06:25:03 -07:00
parent f6e48d0080
commit 1f6d3fe4cc
3 changed files with 69 additions and 20 deletions

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Routing
private readonly Dictionary<string, object> _dictionary;
/// <summary>
/// Creates an empty RouteValueDictionary.
/// Creates an empty <see cref="RouteValueDictionary"/>.
/// </summary>
public RouteValueDictionary()
{
@ -31,28 +31,32 @@ namespace Microsoft.AspNet.Routing
}
/// <summary>
/// Creates a RouteValueDictionary initialized with the provided input values.
/// Creates a <see cref="RouteValueDictionary"/> initialized with the provided input value.
/// </summary>
/// <param name="values">Input values to copy into the dictionary.</param>
public RouteValueDictionary([NotNull] IDictionary<string, object> values)
{
_dictionary = new Dictionary<string, object>(values, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Creates a RouteValueDictionary initialized with the provided input values.
/// </summary>
/// <param name="values">Input values to copy into the dictionary.</param>
/// <param name="obj">An object to initialize the dictionary. The value can be of type
/// <see cref="IDictionary{TKey, TValue}"/> or <see cref="IReadOnlyDictionary{TKey, TValue}"/> or
/// any other object.
/// </param>
/// <remarks>
/// The input parameter is interpreted as a set of key-value-pairs where the property names
/// are keys, and property values are the values, and copied into the dictionary. Only public
/// instance non-index properties are considered.
/// If the value is a dictionary, then its entries are copied. Otherwise the object is interpreted as a set
/// of key-value-pairs where the property names are keys, and property values are the values, and copied
/// into the dictionary. Only public instance non-index properties are considered.
/// </remarks>
public RouteValueDictionary(object obj)
: this()
{
if (obj != null)
{
var keyValuePairCollection = obj as IEnumerable<KeyValuePair<string, object>>;
if (keyValuePairCollection != null)
{
foreach (var kvp in keyValuePairCollection)
{
Add(kvp.Key, kvp.Value);
}
return;
}
var type = obj.GetType();
var allProperties = type.GetRuntimeProperties();

View File

@ -370,11 +370,7 @@ namespace Microsoft.AspNet.Routing.Template
if (_defaults != null)
{
_filters = new RouteValueDictionary(defaults);
foreach (var kvp in _defaults)
{
_filters.Add(kvp.Key, kvp.Value);
}
_filters = new RouteValueDictionary(_defaults);
}
}

View File

@ -168,6 +168,48 @@ namespace Microsoft.AspNet.Routing.Tests
expected);
}
[Fact]
public void CreateFromReadOnlyDictionary_CopiesValues()
{
// Arrange
var dictionary = new Dictionary<string, object>();
dictionary.Add("Name", "James");
dictionary.Add("Age", 30);
var readonlyDictionary = (IReadOnlyDictionary<string, object>)dictionary;
// Act
var dict = new RouteValueDictionary(readonlyDictionary);
// Assert
Assert.Equal(2, dict.Count);
Assert.Equal("James", dict["Name"]);
Assert.Equal(30, dict["Age"]);
}
[Fact]
public void CreateFromReadOnlyDictionary_ModifyRouteValueDictionary()
{
// Arrange
var dictionary = new Dictionary<string, object>();
dictionary.Add("Name", "James");
dictionary.Add("Age", 30);
dictionary.Add("Address", new Address() { City = "Redmond", State = "WA" });
var readonlyDictionary = (IReadOnlyDictionary<string, object>)dictionary;
// Act
var routeValueDictionary = new RouteValueDictionary(readonlyDictionary);
routeValueDictionary.Add("City", "Redmond");
// Assert
Assert.Equal(4, routeValueDictionary.Count);
Assert.Equal("James", routeValueDictionary["Name"]);
Assert.Equal(30, routeValueDictionary["Age"]);
Assert.Equal("Redmond", routeValueDictionary["City"]);
var address = Assert.IsType<Address>(routeValueDictionary["Address"]);
address.State = "Washington";
Assert.Equal("Washington", ((Address)routeValueDictionary["Address"]).State);
}
private static string GetDuplicateKeyErrorMessage()
{
// Gets the exception message when duplicate entries are
@ -233,5 +275,12 @@ namespace Microsoft.AspNet.Routing.Tests
set { }
}
}
private class Address
{
public string City { get; set; }
public string State { get; set; }
}
}
}