From d13f6474d80357b700b9de7e81094e2bfdf945a7 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 21 Jul 2014 14:50:04 -0700 Subject: [PATCH] adding a few tests for areas --- .../ReflectedActionDescriptorProvider.cs | 12 +++ .../Routing/AttributeRoute.cs | 10 +- .../Routing/AttributeRouteTests.cs | 96 +++++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/ReflectedActionDescriptorProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ReflectedActionDescriptorProvider.cs index 1d92526ed7..4c4aecd1dc 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ReflectedActionDescriptorProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ReflectedActionDescriptorProvider.cs @@ -272,6 +272,18 @@ namespace Microsoft.AspNet.Mvc RouteKeyHandling.DenyKey)); } } + else + { + // We still want to add a 'null' for any constraint with DenyKey so that link generation + // works properly. + // + // Consider an action like { area = "", controller = "Home", action = "Index" }. Even if + // it's attribute routed, it needs to know that area must be null to generate a link. + if (!actionDescriptor.RouteValueDefaults.ContainsKey(key)) + { + actionDescriptor.RouteValueDefaults.Add(key, null); + } + } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs index c59df41737..e8bf4b2635 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/AttributeRoute.cs @@ -171,7 +171,15 @@ namespace Microsoft.AspNet.Mvc.Routing object providedValue; if (!context.Values.TryGetValue(key, out providedValue)) { - context.AmbientValues.TryGetValue(key, out providedValue); + // If the required value is an 'empty' route value, then ignore ambient values. + // This handles a case where we're generating a link to an action like: + // { area = "", controller = "Home", action = "Index" } + // + // and the ambient values has a value for area. + if (value != null) + { + context.AmbientValues.TryGetValue(key, out providedValue); + } } return TemplateBinder.RoutePartsEqual(providedValue, value); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRouteTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRouteTests.cs index fc1f9f5935..2d28c29731 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRouteTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/AttributeRouteTests.cs @@ -296,6 +296,102 @@ namespace Microsoft.AspNet.Mvc.Routing Assert.Equal(2, callCount); } + [Fact] + public void AttributeRoute_GenerateLink_ToArea() + { + // Arrange + var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); + entry1.Precedence = 1; + + var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); + entry2.Precedence = 2; + + var next = new StubRouter(); + + var route = CreateAttributeRoute(next, entry1, entry2); + + var context = CreateVirtualPathContext(new { area = "Help", action = "Edit", controller = "Store" }); + + // Act + var path = route.GetVirtualPath(context); + + // Assert + Assert.Equal("Help/Store", path); + } + + [Fact] + public void AttributeRoute_GenerateLink_ToArea_PredecedenceReversed() + { + // Arrange + var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); + entry1.Precedence = 2; + + var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); + entry2.Precedence = 1; + + var next = new StubRouter(); + + var route = CreateAttributeRoute(next, entry1, entry2); + + var context = CreateVirtualPathContext(new { area = "Help", action = "Edit", controller = "Store" }); + + // Act + var path = route.GetVirtualPath(context); + + // Assert + Assert.Equal("Help/Store", path); + } + + [Fact] + public void AttributeRoute_GenerateLink_ToArea_WithAmbientValues() + { + // Arrange + var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); + entry1.Precedence = 1; + + var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); + entry2.Precedence = 2; + + var next = new StubRouter(); + + var route = CreateAttributeRoute(next, entry1, entry2); + + var context = CreateVirtualPathContext( + values: new { action = "Edit", controller = "Store" }, + ambientValues: new { area = "Help" }); + + // Act + var path = route.GetVirtualPath(context); + + // Assert + Assert.Equal("Help/Store", path); + } + + [Fact] + public void AttributeRoute_GenerateLink_OutOfArea_IgnoresAmbientValue() + { + // Arrange + var entry1 = CreateGenerationEntry("Help/Store", new { area = "Help", action = "Edit", controller = "Store" }); + entry1.Precedence = 1; + + var entry2 = CreateGenerationEntry("Store", new { area = (string)null, action = "Edit", controller = "Store" }); + entry2.Precedence = 2; + + var next = new StubRouter(); + + var route = CreateAttributeRoute(next, entry1, entry2); + + var context = CreateVirtualPathContext( + values: new { action = "Edit", controller = "Store" }, + ambientValues: new { area = "Blog" }); + + // Act + var path = route.GetVirtualPath(context); + + // Assert + Assert.Equal("Store", path); + } + private static VirtualPathContext CreateVirtualPathContext(object values, object ambientValues = null) { var httpContext = Mock.Of();