diff --git a/src/Microsoft.AspNet.Mvc.Core/Internal/Routing/LinkGenerationDecisionTree.cs b/src/Microsoft.AspNet.Mvc.Core/Internal/Routing/LinkGenerationDecisionTree.cs index 536e98caeb..d42cc18a9c 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Internal/Routing/LinkGenerationDecisionTree.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Internal/Routing/LinkGenerationDecisionTree.cs @@ -131,24 +131,24 @@ namespace Microsoft.AspNet.Mvc.Internal.Routing public int Compare(LinkGenerationMatch x, LinkGenerationMatch y) { - // For these comparisons lower is better. - + // For this comparison lower is better. if (x.Entry.Order != y.Entry.Order) { return x.Entry.Order.CompareTo(y.Entry.Order); } + if (x.Entry.GenerationPrecedence != y.Entry.GenerationPrecedence) + { + // Reversed because higher is better + return y.Entry.GenerationPrecedence.CompareTo(x.Entry.GenerationPrecedence); + } + if (x.IsFallbackMatch != y.IsFallbackMatch) { // A fallback match is worse than a non-fallback return x.IsFallbackMatch.CompareTo(y.IsFallbackMatch); } - if (x.Entry.Precedence != y.Entry.Precedence) - { - return x.Entry.Precedence.CompareTo(y.Entry.Precedence); - } - return StringComparer.Ordinal.Compare(x.Entry.TemplateText, y.Entry.TemplateText); } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs index ade42dc0aa..f2954c9f4a 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs @@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Mvc.Routing Defaults = routeInfo.Defaults, Constraints = routeInfo.Constraints, Order = routeInfo.Order, - Precedence = routeInfo.Precedence, + GenerationPrecedence = routeInfo.GenerationPrecedence, RequiredLinkValues = routeInfo.ActionDescriptor.RouteValueDefaults, RouteGroup = routeInfo.RouteGroup, Template = routeInfo.ParsedTemplate, @@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.Routing matchingEntries.Add(new AttributeRouteMatchingEntry() { Order = routeInfo.Order, - Precedence = routeInfo.Precedence, + Precedence = routeInfo.MatchPrecedence, Target = _target, RouteName = routeInfo.Name, RouteTemplate = routeInfo.RouteTemplate, @@ -269,7 +269,8 @@ namespace Microsoft.AspNet.Mvc.Routing routeInfo.Order = action.AttributeRouteInfo.Order; - routeInfo.Precedence = AttributeRoutePrecedence.Compute(routeInfo.ParsedTemplate); + routeInfo.MatchPrecedence = AttributeRoutePrecedence.ComputeMatched(routeInfo.ParsedTemplate); + routeInfo.GenerationPrecedence = AttributeRoutePrecedence.ComputeGenerated(routeInfo.ParsedTemplate); routeInfo.Name = action.AttributeRouteInfo.Name; @@ -314,7 +315,9 @@ namespace Microsoft.AspNet.Mvc.Routing public int Order { get; set; } - public decimal Precedence { get; set; } + public decimal MatchPrecedence { get; set; } + + public decimal GenerationPrecedence { get; set; } public string RouteGroup { get; set; } diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRouteLinkGenerationEntry.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRouteLinkGenerationEntry.cs index f971fd13ad..db86e27706 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRouteLinkGenerationEntry.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRouteLinkGenerationEntry.cs @@ -34,9 +34,9 @@ namespace Microsoft.AspNet.Mvc.Routing public int Order { get; set; } /// - /// The precedence of the template. + /// The precedence of the template for link generation. Greater number means higher precedence. /// - public decimal Precedence { get; set; } + public decimal GenerationPrecedence { get; set; } /// /// The name of the route. diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoutePrecedence.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoutePrecedence.cs index d7601eb95c..2edde2f595 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoutePrecedence.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoutePrecedence.cs @@ -13,7 +13,12 @@ namespace Microsoft.AspNet.Mvc.Routing /// public static class AttributeRoutePrecedence { - public static decimal Compute(RouteTemplate template) + // Compute the precedence for matching a provided url + // e.g.: /api/template == 1.1 + // /api/template/{id} == 1.13 + // /api/{id:int} == 1.2 + // /api/template/{id:int} == 1.12 + public static decimal ComputeMatched(RouteTemplate template) { // Each precedence digit corresponds to one decimal place. For example, 3 segments with precedences 2, 1, // and 4 results in a combined precedence of 2.14 (decimal). @@ -23,7 +28,31 @@ namespace Microsoft.AspNet.Mvc.Routing { var segment = template.Segments[i]; - var digit = ComputeDigit(segment); + var digit = ComputeMatchDigit(segment); + Debug.Assert(digit >= 0 && digit < 10); + + precedence += decimal.Divide(digit, (decimal)Math.Pow(10, i)); + } + + return precedence; + } + + // Compute the precedence for generating a url + // e.g.: /api/template == 5.5 + // /api/template/{id} == 5.53 + // /api/{id:int} == 5.4 + // /api/template/{id:int} == 5.54 + public static decimal ComputeGenerated(RouteTemplate template) + { + // Each precedence digit corresponds to one decimal place. For example, 3 segments with precedences 2, 1, + // and 4 results in a combined precedence of 2.14 (decimal). + var precedence = 0m; + + for (var i = 0; i < template.Segments.Count; i++) + { + var segment = template.Segments[i]; + + var digit = ComputeGenerationDigit(segment); Debug.Assert(digit >= 0 && digit < 10); precedence += decimal.Divide(digit, (decimal)Math.Pow(10, i)); @@ -32,17 +61,49 @@ namespace Microsoft.AspNet.Mvc.Routing return precedence; } + // Segments have the following order: + // 5 - Literal segments + // 4 - Multi-part segments && Constrained parameter segments + // 3 - Unconstrained parameter segements + // 2 - Constrained wildcard parameter segments + // 1 - Unconstrained wildcard parameter segments + private static int ComputeGenerationDigit(TemplateSegment segment) + { + if(segment.Parts.Count > 1) + { + return 4; + } + + var part = segment.Parts[0]; + if(part.IsLiteral) + { + return 5; + } + else + { + Debug.Assert(part.IsParameter); + var digit = part.IsCatchAll ? 1 : 3; + + if (part.InlineConstraints != null && part.InlineConstraints.Any()) + { + digit++; + } + + return digit; + } + } + // Segments have the following order: // 1 - Literal segments // 2 - Constrained parameter segments / Multi-part segments // 3 - Unconstrained parameter segments // 4 - Constrained wildcard parameter segments // 5 - Unconstrained wildcard parameter segments - private static int ComputeDigit(TemplateSegment segment) + private static int ComputeMatchDigit(TemplateSegment segment) { if (segment.Parts.Count > 1) { - // Multi-part segments should appear after literal segments but before parameter segments + // Multi-part segments should appear after literal segments and along with parameter segments return 2; } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Internal/Routing/LinkGenerationDecisionTreeTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Internal/Routing/LinkGenerationDecisionTreeTest.cs index d48c7e0310..e55aaf5742 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Internal/Routing/LinkGenerationDecisionTreeTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Internal/Routing/LinkGenerationDecisionTreeTest.cs @@ -247,12 +247,12 @@ namespace Microsoft.AspNet.Mvc.Internal.Routing var entries = new List(); var entry1 = CreateEntry(new { controller = "Store", action = "Buy" }); - entry1.Precedence = 1; + entry1.GenerationPrecedence = 0; entries.Add(entry1); var entry2 = CreateEntry(new { controller = "Store", action = "Buy" }); entry2.Order = 1; - entry2.Precedence = 0; + entry2.GenerationPrecedence = 1; entries.Add(entry2); var tree = new LinkGenerationDecisionTree(entries); @@ -274,11 +274,11 @@ namespace Microsoft.AspNet.Mvc.Internal.Routing var entries = new List(); var entry1 = CreateEntry(new { controller = "Store", action = "Buy" }); - entry1.Precedence = 0; + entry1.GenerationPrecedence = 1; entries.Add(entry1); var entry2 = CreateEntry(new { controller = "Store", action = "Buy" }); - entry2.Precedence = 1; + entry2.GenerationPrecedence = 0; entries.Add(entry2); var tree = new LinkGenerationDecisionTree(entries); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRoutePrecedenceTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRoutePrecedenceTests.cs index 14f91749fe..047b03f170 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRoutePrecedenceTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRoutePrecedenceTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #if DNX451 +using System; using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing.Template; using Microsoft.Extensions.OptionsModel; @@ -16,11 +17,25 @@ namespace Microsoft.AspNet.Mvc.Routing [InlineData("Employees/{id}", "Employees/{employeeId}")] [InlineData("abc", "def")] [InlineData("{x:alpha}", "{x:int}")] - public void Compute_IsEqual(string xTemplate, string yTemplate) + public void ComputeMatched_IsEqual(string xTemplate, string yTemplate) { // Arrange & Act - var xPrededence = Compute(xTemplate); - var yPrededence = Compute(yTemplate); + var xPrededence = ComputeMatched(xTemplate); + var yPrededence = ComputeMatched(yTemplate); + + // Assert + Assert.Equal(xPrededence, yPrededence); + } + + [Theory] + [InlineData("Employees/{id}", "Employees/{employeeId}")] + [InlineData("abc", "def")] + [InlineData("{x:alpha}", "{x:int}")] + public void ComputeGenerated_IsEqual(string xTemplate, string yTemplate) + { + // Arrange & Act + var xPrededence = ComputeGenerated(xTemplate); + var yPrededence = ComputeGenerated(yTemplate); // Assert Assert.Equal(xPrededence, yPrededence); @@ -47,23 +62,63 @@ namespace Microsoft.AspNet.Mvc.Routing [InlineData("abc/{x:int}", "abc/{*x}")] [InlineData("abc/{x}", "abc/{*x}")] [InlineData("{x}/{y:int}", "{x}/{y}")] - public void Compute_IsLessThan(string xTemplate, string yTemplate) + public void ComputeMatched_IsLessThan(string xTemplate, string yTemplate) { // Arrange & Act - var xPrededence = Compute(xTemplate); - var yPrededence = Compute(yTemplate); + var xPrededence = ComputeMatched(xTemplate); + var yPrededence = ComputeMatched(yTemplate); // Assert Assert.True(xPrededence < yPrededence); } - private static decimal Compute(string template) + [Theory] + [InlineData("abc", "a{x}")] + [InlineData("abc", "{x}c")] + [InlineData("abc", "{x:int}")] + [InlineData("abc", "{x}")] + [InlineData("abc", "{*x}")] + [InlineData("{x:int}", "{x}")] + [InlineData("{x:int}", "{*x}")] + [InlineData("a{x}", "{x}")] + [InlineData("{x}c", "{x}")] + [InlineData("a{x}", "{*x}")] + [InlineData("{x}c", "{*x}")] + [InlineData("{x}", "{*x}")] + [InlineData("{*x:maxlength(10)}", "{*x}")] + [InlineData("abc/def", "abc/{x:int}")] + [InlineData("abc/def", "abc/{x}")] + [InlineData("abc/def", "abc/{*x}")] + [InlineData("abc/{x:int}", "abc/{x}")] + [InlineData("abc/{x:int}", "abc/{*x}")] + [InlineData("abc/{x}", "abc/{*x}")] + [InlineData("{x}/{y:int}", "{x}/{y}")] + public void ComputeGenerated_IsGreaterThan(string xTemplate, string yTemplate) + { + // Arrange & Act + var xPrecedence = ComputeGenerated(xTemplate); + var yPrecedence = ComputeGenerated(yTemplate); + + // Assert + Assert.True(xPrecedence > yPrecedence); + } + + private static decimal ComputeMatched(string template) + { + return Compute(template, AttributeRoutePrecedence.ComputeMatched); + } + private static decimal ComputeGenerated(string template) + { + return Compute(template, AttributeRoutePrecedence.ComputeGenerated); + } + + private static decimal Compute(string template, Func func) { var options = new Mock>(); options.SetupGet(o => o.Value).Returns(new RouteOptions()); var parsed = TemplateParser.Parse(template); - return AttributeRoutePrecedence.Compute(parsed); + return func(parsed); } } } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/InnerAttributeRouteTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/InnerAttributeRouteTest.cs index b2b5f1cbf3..f95121c7f7 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/InnerAttributeRouteTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/InnerAttributeRouteTest.cs @@ -360,6 +360,167 @@ namespace Microsoft.AspNet.Mvc.Routing Assert.False(context.IsHandled); } + [Theory] + [InlineData("template", "{*url:alpha}", "/template?url=dingo&id=5")] + [InlineData("{*url:alpha}", "{*url}", "/dingo?id=5")] + [InlineData("{id}", "{*url}", "/5?url=dingo")] + [InlineData("{id}", "{*url:alpha}", "/5?url=dingo")] + [InlineData("{id:int}", "{id}", "/5?url=dingo")] + [InlineData("template/api/{*url}", "template/api", "/template/api/dingo?id=5")] + [InlineData("template/api", "template/{*url}", "/template/api?url=dingo&id=5")] + [InlineData("template/api", "template/api{id}location", "/template/api?url=dingo&id=5")] + [InlineData("template/api{id}location", "template/{id:int}", "/template/api5location?url=dingo")] + public void AttributeRoute_GenerateLink(string firstTemplate, string secondTemplate, string expectedPath) + { + // Arrange + var expectedGroup = CreateRouteGroup(0, firstTemplate); + + string selectedGroup = null; + Action callback = ctx => + { + selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; + ctx.IsBound = true; + }; + + var values = new Dictionary + { + {"url", "dingo" }, + {"id", 5 } + }; + + var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate); + var context = CreateVirtualPathContext( + values: values, + ambientValues: null); + + // Act + var result = route.GetVirtualPath(context); + + // Assert + Assert.NotNull(result); + Assert.Equal(new PathString(expectedPath), result.VirtualPath); + Assert.Same(route, result.Router); + Assert.Empty(result.DataTokens); + Assert.Equal(expectedGroup, selectedGroup); + } + + [Fact] + public void AttributeRoute_GenerateLink_LongerTemplateWithDefaultIsMoreSpecific() + { + // Arrange + var firstTemplate = "template"; + var secondTemplate = "template/{parameter:int=1003}"; + + var expectedGroup = CreateRouteGroup(0, secondTemplate); + + string selectedGroup = null; + Action callback = ctx => + { + selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; + ctx.IsBound = true; + }; + + var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate); + var context = CreateVirtualPathContext( + values: null, + ambientValues: null); + + // Act + var result = route.GetVirtualPath(context); + + // Assert + Assert.NotNull(result); + // The Binder binds to /template + Assert.Equal(new PathString($"/template"), result.VirtualPath); + Assert.Same(route, result.Router); + Assert.Empty(result.DataTokens); + // Even though the path was /template, the group generated from was /template/{paramter:int=1003} + Assert.Equal(expectedGroup, selectedGroup); + } + + [Theory] + [InlineData("template/{parameter:int=5}", "template", "/template/5")] + [InlineData("template/{parameter}", "template", "/template/5")] + [InlineData("template/{parameter}/{id}", "template/{parameter}", "/template/5/1234")] + public void AttributeRoute_GenerateLink_OrderingAgnostic( + string firstTemplate, + string secondTemplate, + string expectedPath) + { + var expectedGroup = CreateRouteGroup(0, firstTemplate); + + string selectedGroup = null; + Action callback = ctx => + { + selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; + ctx.IsBound = true; + }; + + var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate); + var parameter = 5; + var id = 1234; + var values = new Dictionary + { + { nameof(parameter) , parameter}, + { nameof(id), id } + }; + var context = CreateVirtualPathContext( + values: null, + ambientValues: values); + + // Act + var result = route.GetVirtualPath(context); + + // Assert + Assert.NotNull(result); + Assert.Equal(new PathString(expectedPath), result.VirtualPath); + Assert.Same(route, result.Router); + Assert.Empty(result.DataTokens); + Assert.Equal(expectedGroup, selectedGroup); + } + + [Theory] + [InlineData("template", "template/{parameter}", "/template/5")] + [InlineData("template/{parameter}", "template/{parameter}/{id}", "/template/5/1234")] + [InlineData("template", "template/{parameter:int=5}", "/template/5")] + public void AttributeRoute_GenerateLink_UseAvailableVariables( + string firstTemplate, + string secondTemplate, + string expectedPath) + { + // Arrange + var expectedGroup = CreateRouteGroup(0, secondTemplate); + + string selectedGroup = null; + Action callback = ctx => + { + selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey]; + ctx.IsBound = true; + }; + + var route = CreateAttributeRoute(callback, firstTemplate, secondTemplate); + var parameter = 5; + var id = 1234; + var values = new Dictionary + { + { nameof(parameter) , parameter}, + { nameof(id), id } + }; + var context = CreateVirtualPathContext( + values: null, + ambientValues: values); + + // Act + var result = route.GetVirtualPath(context); + + // Assert + Assert.NotNull(result); + Assert.Equal(new PathString(expectedPath), result.VirtualPath); + Assert.Same(route, result.Router); + Assert.Empty(result.DataTokens); + Assert.Equal(expectedGroup, selectedGroup); + } + [Theory] [InlineData("template/5", "template/{parameter:int}")] [InlineData("template/5", "template/{parameter}")] @@ -1228,10 +1389,10 @@ namespace Microsoft.AspNet.Mvc.Routing { // Arrange var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); - entry1.Precedence = 1; + entry1.GenerationPrecedence = 2; var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); - entry2.Precedence = 2; + entry2.GenerationPrecedence = 1; var next = new StubRouter(); @@ -1254,10 +1415,10 @@ namespace Microsoft.AspNet.Mvc.Routing { // Arrange var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); - entry1.Precedence = 2; + entry1.GenerationPrecedence = 1; var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); - entry2.Precedence = 1; + entry2.GenerationPrecedence = 2; var next = new StubRouter(); @@ -1280,10 +1441,10 @@ namespace Microsoft.AspNet.Mvc.Routing { // Arrange var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); - entry1.Precedence = 1; + entry1.GenerationPrecedence = 2; var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); - entry2.Precedence = 2; + entry2.GenerationPrecedence = 1; var next = new StubRouter(); @@ -1308,10 +1469,10 @@ namespace Microsoft.AspNet.Mvc.Routing { // Arrange var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); - entry1.Precedence = 1; + entry1.GenerationPrecedence = 2; var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); - entry2.Precedence = 2; + entry2.GenerationPrecedence = 1; var next = new StubRouter(); @@ -1645,7 +1806,7 @@ namespace Microsoft.AspNet.Mvc.Routing entry.TemplateMatcher = new TemplateMatcher( parsedRouteTemplate, new RouteValueDictionary(new { test_route_group = routeGroup })); - entry.Precedence = AttributeRoutePrecedence.Compute(parsedRouteTemplate); + entry.Precedence = AttributeRoutePrecedence.ComputeMatched(parsedRouteTemplate); entry.Order = order; entry.Constraints = GetRouteConstriants(CreateConstraintResolver(), template, parsedRouteTemplate); return entry; @@ -1690,7 +1851,7 @@ namespace Microsoft.AspNet.Mvc.Routing entry.Defaults = defaults; entry.Binder = new TemplateBinder(entry.Template, defaults); entry.Order = order; - entry.Precedence = AttributeRoutePrecedence.Compute(entry.Template); + entry.GenerationPrecedence = AttributeRoutePrecedence.ComputeGenerated(entry.Template); entry.RequiredLinkValues = new RouteValueDictionary(requiredValues); entry.RouteGroup = CreateRouteGroup(order, template); entry.Name = name; @@ -1779,6 +1940,25 @@ namespace Microsoft.AspNet.Mvc.Routing version: 1); } + private static InnerAttributeRoute CreateAttributeRoute( + Action virtualPathCallback, + string firstTemplate, + string secondTemplate) + { + var next = new Mock(); + next.Setup(n => n.GetVirtualPath(It.IsAny())).Callback(virtualPathCallback) + .Returns((VirtualPathData)null); + + var matchingRoutes = Enumerable.Empty(); + var firstEntry = CreateGenerationEntry(firstTemplate, requiredValues: null); + var secondEntry = CreateGenerationEntry(secondTemplate, requiredValues: null); + + return CreateAttributeRoute( + next.Object, + matchingRoutes, + new[] { secondEntry, firstEntry }); + } + private static InnerAttributeRoute CreateRoutingAttributeRoute( ILoggerFactory loggerFactory = null, params AttributeRouteMatchingEntry[] entries) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs index 55db9b69b2..b7ea579ef7 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs @@ -741,7 +741,7 @@ namespace Microsoft.AspNet.Mvc.Routing [Fact] public void Action_RouteValueInvalidation_DoesNotAffectActionAndController() { - // Arrage + // Arrange var services = GetServices(); var routeBuilder = new RouteBuilder() { @@ -986,7 +986,6 @@ namespace Microsoft.AspNet.Mvc.Routing return services.Object; } - private static IRouter GetRouter( IServiceProvider services, string mockRouteName, diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs index 952c5be3ae..5dc2b6071a 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Net.Http; using System.Reflection; @@ -79,16 +80,16 @@ mypartial get { var expected1 = -@"Hello there!! -Learn More -Hi John ! You are in 2015 year and today is Thursday"; + "Hello there!!" + Environment.NewLine + + "Learn More" + Environment.NewLine + + "Hi John ! You are in 2015 year and today is Thursday"; yield return new[] {"en-GB", expected1 }; var expected2 = -@"Bonjour! -apprendre Encore Plus -Salut John ! Vous êtes en 2015 an aujourd'hui est Thursday"; + "Bonjour!" + Environment.NewLine + + "apprendre Encore Plus" + Environment.NewLine + + "Salut John ! Vous êtes en 2015 an aujourd'hui est Thursday"; yield return new[] { "fr", expected2 }; } } diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs index be11efa8eb..1b23fb489a 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs @@ -500,7 +500,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests public async Task AttributeRoutedAction_AcceptVerbsAndRouteTemplate_IsReachable(string verb, string path) { // Arrange - var expectedUrl = "/Bank"; + var expectedUrl = "/Bank/Update"; var message = new HttpRequestMessage(new HttpMethod(verb), "http://localhost/" + path); // Act