diff --git a/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs index 8cdac84..a37cb32 100644 --- a/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs @@ -42,6 +42,14 @@ namespace Microsoft.AspNet.Routing get { return GetString("TemplateRoute_CannotHaveOptionalParameterInMultiSegment"); } } + /// + /// A catch-all parameter cannot be marked optional. + /// + internal static string TemplateRoute_CatchAllCannotBeOptional + { + get { return GetString("TemplateRoute_CatchAllCannotBeOptional"); } + } + /// /// A catch-all parameter can only appear as the last segment of the route template. /// diff --git a/src/Microsoft.AspNet.Routing/Resources.resx b/src/Microsoft.AspNet.Routing/Resources.resx index 35e3037..5fa3960 100644 --- a/src/Microsoft.AspNet.Routing/Resources.resx +++ b/src/Microsoft.AspNet.Routing/Resources.resx @@ -129,6 +129,9 @@ A path segment that contains more than one section, such as a literal section or a parameter, cannot contain an optional parameter. + + A catch-all parameter cannot be marked optional. + A catch-all parameter can only appear as the last segment of the route template. diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs b/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs index 3b87fae..3a74597 100644 --- a/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs +++ b/src/Microsoft.AspNet.Routing/Template/TemplateParser.cs @@ -178,6 +178,12 @@ namespace Microsoft.AspNet.Routing.Template var isCatchAll = rawName.StartsWith("*", StringComparison.Ordinal); var isOptional = rawName.EndsWith("?", StringComparison.Ordinal); + if (isCatchAll && isOptional) + { + context.Error = Resources.TemplateRoute_CatchAllCannotBeOptional; + return false; + } + rawName = isCatchAll ? rawName.Substring(1) : rawName; rawName = isOptional ? rawName.Substring(0, rawName.Length - 1) : rawName; diff --git a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateParserTests.cs b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateParserTests.cs index 1f3ca9d..9140836 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateParserTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateParserTests.cs @@ -1,8 +1,7 @@ -using System; +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. + +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Xunit; using Xunit.Extensions; @@ -384,6 +383,15 @@ namespace Microsoft.AspNet.Routing.Template.Tests "A path segment that contains more than one section, such as a literal section or a parameter, cannot contain an optional parameter." + Environment.NewLine + "Parameter name: routeTemplate"); } + + [Fact] + public void InvalidTemplate_CatchAllMarkedOptional() + { + Assert.Throws( + () => TemplateParser.Parse("{a}/{*b?}"), + "A catch-all parameter cannot be marked optional." + Environment.NewLine + + "Parameter name: routeTemplate"); + } private class TemplateParsedRouteEqualityComparer : IEqualityComparer { diff --git a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs index 8d80336..a97f956 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTests.cs @@ -722,6 +722,8 @@ namespace Microsoft.AspNet.Routing.Template.Tests // Assert Assert.NotNull(match); + Assert.Equal(2, match.Values.Count); + Assert.Equal("Home", match.Values["controller"]); Assert.Equal("Index", match.Values["action"]); } @@ -737,6 +739,8 @@ namespace Microsoft.AspNet.Routing.Template.Tests // Assert Assert.NotNull(match); + Assert.Equal(1, match.Values.Count); + Assert.Equal("Home", match.Values["controller"]); Assert.False(match.Values.ContainsKey("action")); } @@ -752,6 +756,8 @@ namespace Microsoft.AspNet.Routing.Template.Tests // Assert Assert.NotNull(match); + Assert.Equal(2, match.Values.Count); + Assert.Equal("Home", match.Values["controller"]); Assert.Equal("Index", match.Values["action"]); Assert.False(match.Values.ContainsKey("id")); }