diff --git a/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs b/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs index 37ea3e55c8..dba7b90319 100644 --- a/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs @@ -31,6 +31,16 @@ namespace Microsoft.AspNet.Routing string template, object defaults, object constraints) + { + return MapRoute(routeCollectionBuilder, name, template, defaults, constraints, dataTokens: null); + } + + public static IRouteBuilder MapRoute(this IRouteBuilder routeCollectionBuilder, + string name, + string template, + object defaults, + object constraints, + object dataTokens) { if (routeCollectionBuilder.DefaultHandler == null) { @@ -45,7 +55,9 @@ namespace Microsoft.AspNet.Routing template, ObjectToDictionary(defaults), ObjectToDictionary(constraints), + ObjectToDictionary(dataTokens), inlineConstraintResolver)); + return routeCollectionBuilder; } diff --git a/src/Microsoft.AspNet.Routing/RouteData.cs b/src/Microsoft.AspNet.Routing/RouteData.cs index 842cc99a02..1d818aaec4 100644 --- a/src/Microsoft.AspNet.Routing/RouteData.cs +++ b/src/Microsoft.AspNet.Routing/RouteData.cs @@ -18,5 +18,7 @@ namespace Microsoft.AspNet.Routing public List Routers { get; private set; } public IDictionary Values { get; set; } + + public IDictionary DataTokens { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs index 095d58a5d0..e835c65c22 100644 --- a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs +++ b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs @@ -15,6 +15,7 @@ namespace Microsoft.AspNet.Routing.Template { private readonly IDictionary _defaults; private readonly IDictionary _constraints; + private readonly IDictionary _dataTokens; private readonly IRouter _target; private readonly RouteTemplate _parsedTemplate; private readonly string _routeTemplate; @@ -24,7 +25,12 @@ namespace Microsoft.AspNet.Routing.Template private ILogger _constraintLogger; public TemplateRoute(IRouter target, string routeTemplate, IInlineConstraintResolver inlineConstraintResolver) - : this(target, routeTemplate, null, null, inlineConstraintResolver) + : this(target, + routeTemplate, + defaults: null, + constraints: null, + dataTokens: null, + inlineConstraintResolver: inlineConstraintResolver) { } @@ -32,8 +38,9 @@ namespace Microsoft.AspNet.Routing.Template string routeTemplate, IDictionary defaults, IDictionary constraints, + IDictionary dataTokens, IInlineConstraintResolver inlineConstraintResolver) - : this(target, null, routeTemplate, defaults, constraints, inlineConstraintResolver) + : this(target, null, routeTemplate, defaults, constraints, dataTokens, inlineConstraintResolver) { } @@ -42,6 +49,7 @@ namespace Microsoft.AspNet.Routing.Template string routeTemplate, IDictionary defaults, IDictionary constraints, + IDictionary dataTokens, IInlineConstraintResolver inlineConstraintResolver) { _target = target; @@ -50,6 +58,7 @@ namespace Microsoft.AspNet.Routing.Template _defaults = defaults ?? new RouteValueDictionary(); _constraints = RouteConstraintBuilder.BuildConstraints(constraints, _routeTemplate) ?? new Dictionary(); + _dataTokens = dataTokens ?? new Dictionary(StringComparer.OrdinalIgnoreCase); // The parser will throw for invalid routes. _parsedTemplate = TemplateParser.Parse(RouteTemplate, inlineConstraintResolver); @@ -66,6 +75,11 @@ namespace Microsoft.AspNet.Routing.Template get { return _defaults; } } + public IDictionary DataTokens + { + get { return _dataTokens; } + } + public string RouteTemplate { get { return _routeTemplate; } @@ -117,6 +131,7 @@ namespace Microsoft.AspNet.Routing.Template RouteDirection.IncomingRequest, _constraintLogger)) { + context.RouteData.DataTokens = _dataTokens; await _target.RouteAsync(context); if (_logger.IsEnabled(TraceType.Information)) diff --git a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTest.cs b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTest.cs index 44717645a0..3601bf29f9 100644 --- a/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTest.cs +++ b/test/Microsoft.AspNet.Routing.Tests/Template/TemplateRouteTest.cs @@ -662,7 +662,61 @@ namespace Microsoft.AspNet.Routing.Template #endregion -#region Route Registration + #region Route Registration + + public static IEnumerable DataTokens + { + get + { + yield return new object[] { + new Dictionary { { "key1", "data1" }, { "key2", 13 } }, + new Dictionary { { "key1", "data1" }, { "key2", 13 } }, + }; + yield return new object[] { + new RouteValueDictionary { { "key1", "data1" }, { "key2", 13 } }, + new Dictionary { { "key1", "data1" }, { "key2", 13 } }, + }; + yield return new object[] { + new object(), + new Dictionary(), + }; + yield return new object[] { + null, + new Dictionary() + }; + yield return new object[] { + new { key1 = "data1", key2 = 13 }, + new Dictionary { { "key1", "data1" }, { "key2", 13 } }, + }; + } + } + + [Theory] + [MemberData("DataTokens")] + public void RegisteringRoute_WithDataTokens_AbleToAddTheRoute(object dataToken, + IDictionary expectedDictionary) + { + // Arrange + var routeBuilder = CreateRouteBuilder(); + + // Act + routeBuilder.MapRoute("mockName", + "{controller}/{action}", + defaults: null, + constraints: null, + dataTokens: dataToken); + + // Assert + var templateRoute = (TemplateRoute)routeBuilder.Routes[0]; + + // Assert + Assert.Equal(expectedDictionary.Count, templateRoute.DataTokens.Count); + foreach (var expectedKey in expectedDictionary.Keys) + { + Assert.True(templateRoute.DataTokens.ContainsKey(expectedKey)); + Assert.Equal(expectedDictionary[expectedKey], templateRoute.DataTokens[expectedKey]); + } + } [Fact] public void RegisteringRouteWithInvalidConstraints_Throws() @@ -794,12 +848,19 @@ namespace Microsoft.AspNet.Routing.Template return new TemplateRoute(CreateTarget(accept), template, _inlineConstraintResolver); } - private static TemplateRoute CreateRoute(string template, object defaults, bool accept = true, object constraints = null) + private static TemplateRoute CreateRoute(string template, + object defaults, + bool accept = true, + object constraints = null, + object dataTokens = null) { return new TemplateRoute(CreateTarget(accept), template, new RouteValueDictionary(defaults), - (constraints as IDictionary) ?? new RouteValueDictionary(constraints), + (constraints as IDictionary) ?? + new RouteValueDictionary(constraints), + (dataTokens as IDictionary) ?? + new RouteValueDictionary(constraints), _inlineConstraintResolver); } @@ -809,6 +870,7 @@ namespace Microsoft.AspNet.Routing.Template template, new RouteValueDictionary(), constraints: null, + dataTokens: null, inlineConstraintResolver: _inlineConstraintResolver); } @@ -818,6 +880,7 @@ namespace Microsoft.AspNet.Routing.Template template, new RouteValueDictionary(defaults), constraints: null, + dataTokens: null, inlineConstraintResolver: _inlineConstraintResolver); }