diff --git a/Mvc.sln b/Mvc.sln
index e5781ed5c3..502a66526f 100644
--- a/Mvc.sln
+++ b/Mvc.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.21806.0
+VisualStudioVersion = 14.0.21727.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@@ -45,6 +45,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutofacWebSite", "test\WebS
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestConfiguration", "test\WebSites\Microsoft.AspNet.Mvc.TestConfiguration\Microsoft.AspNet.Mvc.TestConfiguration.kproj", "{680D75ED-601F-4D86-B01B-1072D0C31B8C}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RoutingWebSite", "test\WebSites\RoutingWebSite\RoutingWebSite.kproj", "{42CDBF4A-E238-4C0F-A416-44588363EB4C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -225,6 +227,16 @@ Global
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|x86.ActiveCfg = Release|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -248,5 +260,6 @@ Global
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{07C0E921-FCBB-458C-AC11-3D01CE68B16B} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{680D75ED-601F-4D86-B01B-1072D0C31B8C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
+ {42CDBF4A-E238-4C0F-A416-44588363EB4C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
EndGlobalSection
EndGlobal
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj
index d5a62515f4..c2b262acd3 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj
@@ -33,6 +33,7 @@
+
@@ -42,4 +43,4 @@
-
\ No newline at end of file
+
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs
new file mode 100644
index 0000000000..0281dbc520
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs
@@ -0,0 +1,151 @@
+// Copyright (c) Microsoft Open Technologies, Inc. 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.Threading.Tasks;
+using Newtonsoft.Json;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.TestHost;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.FunctionalTests
+{
+ public class RoutingTests
+ {
+ private readonly IServiceProvider _services;
+ private readonly Action _app = new RoutingWebSite.Startup().Configure;
+
+ public RoutingTests()
+ {
+ _services = TestHelper.CreateServices("RoutingWebSite");
+ }
+
+ [Fact]
+ public async Task ConventionRoutedController_ActionIsReachable()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+
+ // Act
+ var response = await client.GetAsync("http://localhost/Home/Index");
+
+ // Assert
+ Assert.Equal(200, response.StatusCode);
+
+ var body = await response.ReadBodyAsStringAsync();
+ var result = JsonConvert.DeserializeObject(body);
+
+ Assert.Contains("/Home/Index", result.ExpectedUrls);
+ Assert.Equal("Home", result.Controller);
+ Assert.Equal("Index", result.Action);
+ Assert.Equal(
+ new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "controller", "Home" },
+ { "action", "Index" },
+ },
+ result.RouteValues);
+ }
+
+ [Fact]
+ public async Task ConventionRoutedController_ActionIsReachable_WithDefaults()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+
+ // Act
+ var response = await client.GetAsync("http://localhost/");
+
+ // Assert
+ Assert.Equal(200, response.StatusCode);
+
+ var body = await response.ReadBodyAsStringAsync();
+ var result = JsonConvert.DeserializeObject(body);
+
+ Assert.Contains("/", result.ExpectedUrls);
+ Assert.Equal("Home", result.Controller);
+ Assert.Equal("Index", result.Action);
+ Assert.Equal(
+ new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "controller", "Home" },
+ { "action", "Index" },
+ },
+ result.RouteValues);
+ }
+
+ [Fact]
+ public async Task ConventionRoutedController_NonActionIsNotReachable()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+
+ // Act
+ var response = await client.GetAsync("http://localhost/Home/NotAnAction");
+
+ // Assert
+ Assert.Equal(404, response.StatusCode);
+ }
+
+ [Fact]
+ public async Task ConventionRoutedController_InArea_ActionIsReachable()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+
+ // Act
+ var response = await client.GetAsync("http://localhost/Travel/Flight/Index");
+
+ // Assert
+ Assert.Equal(200, response.StatusCode);
+
+ var body = await response.ReadBodyAsStringAsync();
+ var result = JsonConvert.DeserializeObject(body);
+
+ Assert.Contains("/Travel/Flight/Index", result.ExpectedUrls);
+ Assert.Equal("Flight", result.Controller);
+ Assert.Equal("Index", result.Action);
+ Assert.Equal(
+ new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "area", "Travel" },
+ { "controller", "Flight" },
+ { "action", "Index" },
+ },
+ result.RouteValues);
+ }
+
+ [Fact]
+ public async Task ConventionRoutedController_InArea_ActionBlockedByHttpMethod()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+
+ // Act
+ var response = await client.GetAsync("http://localhost/Travel/Flight/BuyTickets");
+
+ // Assert
+ Assert.Equal(404, response.StatusCode);
+ }
+
+ // See TestResponseGenerator in RoutingWebSite for the code that generates this data.
+ private class RoutingResult
+ {
+ public string[] ExpectedUrls { get; set; }
+
+ public string ActualUrl { get; set; }
+
+ public Dictionary RouteValues { get; set; }
+
+ public string Action { get; set; }
+
+ public string Controller { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json
index 98d04a030f..4f78736822 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json
@@ -12,6 +12,7 @@
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Microsoft.Framework.Runtime.Interfaces": "1.0.0-*",
+ "RoutingWebSite": "",
"Xunit.KRunner": "1.0.0-*"
},
"commands": {
diff --git a/test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs b/test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs
new file mode 100644
index 0000000000..ae5730e9a0
--- /dev/null
+++ b/test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs
@@ -0,0 +1,28 @@
+using Microsoft.AspNet.Mvc;
+using System;
+
+namespace RoutingWebSite
+{
+ // This controller is reachable via traditional routing.
+ [Area("Travel")]
+ public class FlightController
+ {
+ private readonly TestResponseGenerator _generator;
+
+ public FlightController(TestResponseGenerator generator)
+ {
+ _generator = generator;
+ }
+
+ public IActionResult Index()
+ {
+ return _generator.Generate("/Travel/Flight", "/Travel/Flight/Index");
+ }
+
+ [HttpPost]
+ public IActionResult BuyTickets()
+ {
+ return _generator.Generate("/Travel/Flight/BuyTickets");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/RoutingWebSite/Controllers/HomeController.cs b/test/WebSites/RoutingWebSite/Controllers/HomeController.cs
new file mode 100644
index 0000000000..ba4a876f7c
--- /dev/null
+++ b/test/WebSites/RoutingWebSite/Controllers/HomeController.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNet.Mvc;
+
+namespace RoutingWebSite
+{
+ // This controller is reachable via traditional routing.
+ public class HomeController : Controller
+ {
+ private readonly TestResponseGenerator _generator;
+
+ public HomeController(TestResponseGenerator generator)
+ {
+ _generator = generator;
+ }
+
+ public IActionResult Index()
+ {
+ return _generator.Generate("/", "/Home", "/Home/Index");
+ }
+
+ public IActionResult About()
+ {
+ return _generator.Generate();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/RoutingWebSite/RoutingWebSite.kproj b/test/WebSites/RoutingWebSite/RoutingWebSite.kproj
new file mode 100644
index 0000000000..6aceb03b05
--- /dev/null
+++ b/test/WebSites/RoutingWebSite/RoutingWebSite.kproj
@@ -0,0 +1,40 @@
+
+
+
+ 12.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+ Debug
+ AnyCPU
+
+
+
+ 42cdbf4a-e238-4c0f-a416-44588363eb4c
+ Web
+
+
+ ConsoleDebugger
+
+
+ WebDebugger
+
+
+
+
+ 2.0
+
+
+ 11178
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/WebSites/RoutingWebSite/Startup.cs b/test/WebSites/RoutingWebSite/Startup.cs
new file mode 100644
index 0000000000..eb11249f9c
--- /dev/null
+++ b/test/WebSites/RoutingWebSite/Startup.cs
@@ -0,0 +1,33 @@
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.Mvc;
+using Microsoft.AspNet.Routing;
+using Microsoft.Framework.ConfigurationModel;
+using Microsoft.Framework.DependencyInjection;
+
+namespace RoutingWebSite
+{
+ public class Startup
+ {
+ public void Configure(IBuilder app)
+ {
+ var configuration = app.GetTestConfiguration();
+
+ app.UseServices(services =>
+ {
+ services.AddMvc(configuration);
+
+ services.AddScoped();
+ });
+
+ app.UseMvc(routes =>
+ {
+ routes.MapRoute("areaRoute",
+ "{area:exists}/{controller}/{action}",
+ new { controller = "Home", action = "Index" });
+
+ routes.MapRoute("ActionAsMethod", "{controller}/{action}",
+ defaults: new { controller = "Home", action = "Index" });
+ });
+ }
+ }
+}
diff --git a/test/WebSites/RoutingWebSite/TestResponseGenerator.cs b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs
new file mode 100644
index 0000000000..53b9a8abcf
--- /dev/null
+++ b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNet.Mvc;
+using Microsoft.Framework.DependencyInjection;
+
+namespace RoutingWebSite
+{
+ // Generates a response based on the expected URL and action context
+ public class TestResponseGenerator
+ {
+ private readonly ActionContext _actionContext;
+
+ public TestResponseGenerator(IContextAccessor contextAccessor)
+ {
+ _actionContext = contextAccessor.Value;
+ if (_actionContext == null)
+ {
+ throw new InvalidOperationException("ActionContext should not be null here.");
+ }
+ }
+
+ public JsonResult Generate(params string[] expectedUrls)
+ {
+ return new JsonResult(new
+ {
+ expectedUrls = expectedUrls,
+ actualUrl = _actionContext.HttpContext.Request.Path.Value,
+ routeValues = _actionContext.RouteData.Values,
+
+ action = _actionContext.ActionDescriptor.Name,
+ controller = ((ReflectedActionDescriptor)_actionContext.ActionDescriptor).ControllerDescriptor.Name,
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/RoutingWebSite/project.json b/test/WebSites/RoutingWebSite/project.json
new file mode 100644
index 0000000000..465e43af98
--- /dev/null
+++ b/test/WebSites/RoutingWebSite/project.json
@@ -0,0 +1,11 @@
+{
+ "dependencies": {
+ "Helios": "1.0.0-*",
+ "Microsoft.AspNet.Mvc": "",
+ "Microsoft.AspNet.Mvc.TestConfiguration": ""
+ },
+ "configurations": {
+ "net45": { },
+ "k10": { }
+ }
+}