* Add a sample for SubAreas

This commit is contained in:
ryanbrandenburg 2015-10-19 14:16:11 -07:00
parent 947d070678
commit cad7d44686
19 changed files with 416 additions and 1 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24711.0
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@ -99,6 +99,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "LocalizationSample.Web", "s
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ActionConstraintSample.Web", "samples\ActionConstraintSample.Web\ActionConstraintSample.Web.xproj", "{EE0BD773-4D47-4AA8-8472-5A938A3953BA}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "samples\MvcSubAreaSample.Web\MvcSubAreaSample.Web.xproj", "{E1D45BAF-3967-4D81-9217-22AA54941BF5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -591,6 +593,18 @@ Global
{EE0BD773-4D47-4AA8-8472-5A938A3953BA}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EE0BD773-4D47-4AA8-8472-5A938A3953BA}.Release|x86.ActiveCfg = Release|Any CPU
{EE0BD773-4D47-4AA8-8472-5A938A3953BA}.Release|x86.Build.0 = Release|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|x86.ActiveCfg = Debug|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Debug|x86.Build.0 = Debug|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Any CPU.Build.0 = Release|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|x86.ActiveCfg = Release|Any CPU
{E1D45BAF-3967-4D81-9217-22AA54941BF5}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -638,5 +652,6 @@ Global
{DAB1252D-577C-4912-98BE-1A812BF83F86} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{FCFE6024-2720-49B4-8257-9DBC6114F0F1} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{EE0BD773-4D47-4AA8-8472-5A938A3953BA} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{E1D45BAF-3967-4D81-9217-22AA54941BF5} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
EndGlobalSection
EndGlobal

15
Mvc.sln
View File

@ -144,6 +144,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SimpleWebSite", "test\WebSi
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InlineConstraintSample.Web", "samples\InlineConstraintSample.Web\InlineConstraintSample.Web.xproj", "{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSubAreaSample.Web", "samples\MvcSubAreaSample.Web\MvcSubAreaSample.Web.xproj", "{45F6B3B6-D114-4D77-84D6-561B3957F341}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -865,6 +867,18 @@ Global
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|x86.ActiveCfg = Release|Any CPU
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE}.Release|x86.Build.0 = Release|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|x86.ActiveCfg = Debug|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Debug|x86.Build.0 = Debug|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Any CPU.Build.0 = Release|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.ActiveCfg = Release|Any CPU
{45F6B3B6-D114-4D77-84D6-561B3957F341}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -935,5 +949,6 @@ Global
{EE0BD773-4D47-4AA8-8472-5A938A3953BA} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{396B40D7-AC70-49A7-B33C-ED42129FEBE3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{EA34877F-1AC1-42B7-B4E6-15A093F40CAE} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{45F6B3B6-D114-4D77-84D6-561B3957F341} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,18 @@
// 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 Microsoft.AspNet.Mvc;
namespace MvcSubAreaSample.Web.Restaurant.Hours
{
[Area("Restaurant")]
[SubArea("Hours")]
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
}
}

View File

@ -0,0 +1,11 @@
@{
Layout = "/Views/Shared/_Layout.cshtml";
ViewData["Title"] = "Home Page";
}
<div>
<h2>Hours</h2>
<ul>
<li>9-5 M-F</li>
</ul>
</div>

View File

@ -0,0 +1,18 @@
// 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 Microsoft.AspNet.Mvc;
namespace MvcSubAreaSample.Web.Restaurant.Menu
{
[Area("Restaurant")]
[SubArea("Menu")]
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
}
}

View File

@ -0,0 +1,12 @@
@{
ViewData["Title"] = "Home Page";
Layout = "/Views/Shared/_Layout.cshtml";
}
<div>
<h2>Menu</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>

View File

@ -0,0 +1,17 @@
// 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 Microsoft.AspNet.Mvc;
namespace MvcSubAreaSample.Web.Restaurant
{
[Area("Restaurant")]
public class HomeController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
}
}

View File

@ -0,0 +1,15 @@
@addTagHelper *, Microsoft.AspNet.Mvc.TagHelpers
@{
Layout = "/Views/Shared/_Layout.cshtml";
ViewData["Title"] = "Home Page";
}
<div class="row">
<div class="col-md-3">
<h2>Areas</h2>
<ul>
<li><a asp-controller="Home" asp-action="Index" asp-route-area="Restaurant" asp-route-subarea="Menu">Menu</a></li>
<li><a asp-controller="Home" asp-action="Index" asp-route-area="Restaurant" asp-route-subarea="Hours">Hours</a></li>
</ul>
</div>
</div>

View File

@ -0,0 +1,34 @@
// 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 Microsoft.AspNet.Mvc;
namespace MvcSubAreaSample.Web
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
public IActionResult Error()
{
return View("~/Views/Shared/Error.cshtml");
}
}
}

View File

@ -0,0 +1,49 @@
// 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 Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Extensions.DependencyInjection;
namespace MvcSubAreaSample.Web
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new SubAreaViewLocationExpander());
});
services.AddMvc();
return services.BuildServiceProvider();
}
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app)
{
// Add MVC to the request pipeline.
app.UseFileServer();
app.UseMvc(routes =>
{
routes.MapRoute("subarearoute", "{area:exists}/{subarea:exists}/{controller=Home}/{action=Index}");
routes.MapRoute("areaRoute", "{area:exists}/{controller=Home}/{action=Index}");
routes.MapRoute("controllerActionRoute", "{controller=Home}/{action=Index}");
});
}
public static void Main(string[] args)
{
var application = new WebApplicationBuilder()
.UseConfiguration(WebApplicationConfiguration.GetDefault(args))
.UseStartup<Startup>()
.Build();
application.Run();
}
}
}

View File

@ -0,0 +1,21 @@
// 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 Microsoft.AspNet.Mvc.Infrastructure;
namespace MvcSubAreaSample.Web
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class SubAreaAttribute : RouteConstraintAttribute
{
public SubAreaAttribute(string name)
: base("subarea", name, blockNonAttributedActions: true)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentException("SubArea name must not be null or empty.", nameof(name));
}
}
}
}

View File

@ -0,0 +1,41 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.Razor;
namespace MvcSubAreaSample.Web
{
public class SubAreaViewLocationExpander : IViewLocationExpander
{
private const string _subAreaKey = "subarea";
public IEnumerable<string> ExpandViewLocations(
ViewLocationExpanderContext context,
IEnumerable<string> viewLocations)
{
if (context.Values.ContainsKey(_subAreaKey))
{
var subArea = RazorViewEngine.GetNormalizedRouteValue(context.ActionContext, _subAreaKey);
var subareaViewLocations = new string[]
{
"/Areas/{2}/Areas/" + subArea + "/Views/{1}/{0}.cshtml"
};
viewLocations = subareaViewLocations.Concat(viewLocations);
}
return viewLocations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
var subArea = context.ActionContext.ActionDescriptor.RouteConstraints.FirstOrDefault(
s => s.RouteKey == "subarea" && !string.IsNullOrEmpty(s.RouteValue));
if (subArea != null)
{
context.Values[_subAreaKey] = subArea.RouteValue;
}
}
}
}

View File

@ -0,0 +1,15 @@

@addTagHelper *, Microsoft.AspNet.Mvc.TagHelpers
@{
ViewData["Title"] = "Home Page";
Layout = "/Views/Shared/_Layout.cshtml";
}
<div class="row">
<div class="col-md-3">
<h2>Areas</h2>
<ul>
<li><a asp-route-area="Restaurant" asp-controller="Home" asp-action="Index">Restaurant</a></li>
</ul>
</div>
</div>

View File

@ -0,0 +1,46 @@
<!DOCTYPE html>
@addTagHelper *, Microsoft.AspNet.Mvc.TagHelpers
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - MvcSubAreaSample.Web</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-controller="Home" asp-action="Index" class="navbar-brand">MvcSubAreaSample.Web</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-route-area="Restaurant" asp-route-subarea="Menu" asp-controller="Home" asp-action="Index">Menu</a></li>
<li><a asp-route-area="Restaurant" asp-route-subarea="Hours" asp-controller="Home" asp-action="Index">Hours</a></li>
<li><a asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>&copy; 2015 - MvcSubAreaSample.Web</p>
</footer>
</div>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/lib/hammer.js/hammer.js"></script>
<script src="~/lib/bootstrap-touch-carousel/dist/js/bootstrap-touch-carousel.js"></script>
@RenderSection("scripts", required: false)
</body>
</html>

View File

@ -0,0 +1,3 @@
{
"server": "Microsoft.AspNet.Server.Kestrel"
}

View File

@ -0,0 +1,19 @@
{
"compilationOptions": {
"emitEntryPoint": true
},
"commands": {
"web": "MvcSubAreaSample.Web"
},
"dependencies": {
"Microsoft.AspNet.Diagnostics": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-*",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
</system.webServer>
</configuration>

View File

@ -0,0 +1,56 @@
// 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.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
public class SubAreaTests : IClassFixture<MvcTestFixture<MvcSubAreaSample.Web.Startup>>
{
public SubAreaTests(MvcTestFixture<MvcSubAreaSample.Web.Startup> fixture)
{
Client = fixture.Client;
}
public HttpClient Client { get; }
[Fact]
public async Task SubArea_Menu()
{
// Arrange & Act
var response = await Client.GetAsync("/Restaurant/Menu/Home/Index");
var content = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Contains("Item 1", content);
}
[Fact]
public async Task SubArea_Hours()
{
// Arrange & Act
var response = await Client.GetAsync("/Restaurant/Hours/Home/Index");
var content = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Contains("9-5 M-F", content);
}
[Fact]
public async Task SubArea_Home()
{
// Arrange & Act
var response = await Client.GetAsync("/");
var content = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Contains("Areas", content);
}
}
}

View File

@ -36,6 +36,7 @@
"Microsoft.Extensions.Configuration.Json": "1.0.0-*",
"Microsoft.Extensions.Logging.Testing": "1.0.0-*",
"MvcSandbox": "1.0.0",
"MvcSubAreaSample.Web": "1.0.0",
"PrecompilationWebSite": "1.0.0",
"RazorPageExecutionInstrumentationWebSite": "1.0.0",
"RazorWebSite": "1.0.0",