diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateBinder.cs b/src/Microsoft.AspNet.Routing/Template/TemplateBinder.cs index 7b562ba542..1b43576845 100644 --- a/src/Microsoft.AspNet.Routing/Template/TemplateBinder.cs +++ b/src/Microsoft.AspNet.Routing/Template/TemplateBinder.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Diagnostics; using System.Globalization; using System.Text.Encodings.Web; @@ -290,28 +291,34 @@ namespace Microsoft.AspNet.Routing.Template continue; } - var converted = Convert.ToString(kvp.Value, CultureInfo.InvariantCulture); - if (string.IsNullOrEmpty(converted)) + var values = kvp.Value as IEnumerable; + if (values != null && !(values is string)) { - continue; - } - - if (!wroteFirst) - { - context.Writer.Write('?'); - wroteFirst = true; + foreach (var value in values) + { + wroteFirst |= AddParameterToContext(context, kvp.Key, value, wroteFirst); + } } else { - context.Writer.Write('&'); + wroteFirst |= AddParameterToContext(context, kvp.Key, kvp.Value, wroteFirst); } + } + return context.ToString(); + } - _urlEncoder.Encode(context.Writer, kvp.Key); + private bool AddParameterToContext(UriBuildingContext context, string key, object value, bool wroteFirst) + { + var converted = Convert.ToString(value, CultureInfo.InvariantCulture); + if (!string.IsNullOrEmpty(converted)) + { + context.Writer.Write(wroteFirst ? '&' : '?'); + _urlEncoder.Encode(context.Writer, key); context.Writer.Write('='); _urlEncoder.Encode(context.Writer, converted); + return true; } - - return context.ToString(); + return false; } private TemplatePart GetParameter(string name) diff --git a/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs b/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs index f4d3b422a5..c9c22cabc3 100644 --- a/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Http; @@ -631,6 +630,78 @@ namespace Microsoft.AspNet.Routing Assert.Null(path); } + [Fact] + public void GetVirtualPath_ForListOfStrings() + { + // Arrange + var route = CreateRoute("{controller}/{action}"); + var context = CreateVirtualPathContext( + new { color = new List { "red", "green", "blue" } }, + new { controller = "Home", action = "Index" }); + + // Act + var pathData = route.GetVirtualPath(context); + + // Assert + Assert.Equal(new PathString("/Home/Index?color=red&color=green&color=blue"), pathData.VirtualPath); + Assert.Same(route, pathData.Router); + Assert.Empty(pathData.DataTokens); + } + + [Fact] + public void GetVirtualPath_ForListOfInts() + { + // Arrange + var route = CreateRoute("{controller}/{action}"); + var context = CreateVirtualPathContext( + new { items = new List { 10, 20, 30 } }, + new { controller = "Home", action = "Index" }); + + // Act + var pathData = route.GetVirtualPath(context); + + // Assert + Assert.Equal(new PathString("/Home/Index?items=10&items=20&items=30"), pathData.VirtualPath); + Assert.Same(route, pathData.Router); + Assert.Empty(pathData.DataTokens); + } + + [Fact] + public void GetVirtualPath_ForList_Empty() + { + // Arrange + var route = CreateRoute("{controller}/{action}"); + var context = CreateVirtualPathContext( + new { color = new List { } }, + new { controller = "Home", action = "Index" }); + + // Act + var pathData = route.GetVirtualPath(context); + + // Assert + Assert.Equal(new PathString("/Home/Index"), pathData.VirtualPath); + Assert.Same(route, pathData.Router); + Assert.Empty(pathData.DataTokens); + } + + [Fact] + public void GetVirtualPath_ForList_StringWorkaround() + { + // Arrange + var route = CreateRoute("{controller}/{action}"); + var context = CreateVirtualPathContext( + new { page = 1, color = new List { "red", "green", "blue" }, message = "textfortest" }, + new { controller = "Home", action = "Index" }); + + // Act + var pathData = route.GetVirtualPath(context); + + // Assert + Assert.Equal(new PathString("/Home/Index?page=1&color=red&color=green&color=blue&message=textfortest"), pathData.VirtualPath); + Assert.Same(route, pathData.Router); + Assert.Empty(pathData.DataTokens); + } + [Theory] [MemberData("DataTokensTestData")] public void GetVirtualPath_ReturnsDataTokens_WhenTargetReturnsVirtualPathData(