Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.

Commit 431036a

Browse files
authored
Add Controller for multiple areas sample (#262)
Sample for aspnet/Mvc#6637
1 parent 0a7ec82 commit 431036a

File tree

13 files changed

+238
-1
lines changed

13 files changed

+238
-1
lines changed

Entropy.sln

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Microsoft Visual Studio Solution File, Format Version 12.00
22
# Visual Studio 15
3-
VisualStudioVersion = 15.0.26413.2
3+
VisualStudioVersion = 15.0.26824.3000
44
MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Builder", "Builder", "{097807B3-FE74-4DCD-B76B-2FCE1A272BE5}"
66
EndProject
@@ -126,6 +126,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{DA474CFD
126126
EndProject
127127
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Entropy.FunctionalTests", "test\Entropy.FunctionalTests\Entropy.FunctionalTests.csproj", "{3D0B3DD1-6779-4E8F-BFBC-809497F7B30F}"
128128
EndProject
129+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mvc.ControllerForMultipleAreasSample", "samples\Mvc.ControllerForMultipleAreasSample\Mvc.ControllerForMultipleAreasSample.csproj", "{8A61FA46-3FD4-42BE-80C6-E5931387590C}"
130+
EndProject
129131
Global
130132
GlobalSection(SolutionConfigurationPlatforms) = preSolution
131133
Debug|Any CPU = Debug|Any CPU
@@ -688,6 +690,18 @@ Global
688690
{3D0B3DD1-6779-4E8F-BFBC-809497F7B30F}.Release|x64.Build.0 = Release|Any CPU
689691
{3D0B3DD1-6779-4E8F-BFBC-809497F7B30F}.Release|x86.ActiveCfg = Release|Any CPU
690692
{3D0B3DD1-6779-4E8F-BFBC-809497F7B30F}.Release|x86.Build.0 = Release|Any CPU
693+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
694+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Debug|Any CPU.Build.0 = Debug|Any CPU
695+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Debug|x64.ActiveCfg = Debug|Any CPU
696+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Debug|x64.Build.0 = Debug|Any CPU
697+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Debug|x86.ActiveCfg = Debug|Any CPU
698+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Debug|x86.Build.0 = Debug|Any CPU
699+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Release|Any CPU.ActiveCfg = Release|Any CPU
700+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Release|Any CPU.Build.0 = Release|Any CPU
701+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Release|x64.ActiveCfg = Release|Any CPU
702+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Release|x64.Build.0 = Release|Any CPU
703+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Release|x86.ActiveCfg = Release|Any CPU
704+
{8A61FA46-3FD4-42BE-80C6-E5931387590C}.Release|x86.Build.0 = Release|Any CPU
691705
EndGlobalSection
692706
GlobalSection(SolutionProperties) = preSolution
693707
HideSolutionNode = FALSE
@@ -750,5 +764,9 @@ Global
750764
{EB0FB22E-DF89-4044-8EF2-F7790E8B0216} = {CD3A2B49-E781-4766-B775-6FF3672AE308}
751765
{FDD8875D-00D6-4E8C-9E21-D90C0A2C81B7} = {CD3A2B49-E781-4766-B775-6FF3672AE308}
752766
{3D0B3DD1-6779-4E8F-BFBC-809497F7B30F} = {C03BF7E1-ECDF-48D0-85CD-A454AA28D80C}
767+
{8A61FA46-3FD4-42BE-80C6-E5931387590C} = {5BCA2B8A-37DA-4A88-A221-3D5B4796B07F}
768+
EndGlobalSection
769+
GlobalSection(ExtensibilityGlobals) = postSolution
770+
SolutionGuid = {5DF584CA-249D-432C-BBA9-4498414C8E97}
753771
EndGlobalSection
754772
EndGlobal
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Manage View
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Products View
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Services View
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNetCore.Mvc;
5+
6+
namespace ControllerForMultipleAreasSample
7+
{
8+
[MultipleAreas("Products", "Services", "Manage")]
9+
public class HomeController : Controller
10+
{
11+
public IActionResult Index()
12+
{
13+
return View();
14+
}
15+
}
16+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Linq;
6+
7+
namespace ControllerForMultipleAreasSample
8+
{
9+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
10+
public class MultipleAreasAttribute : Attribute
11+
{
12+
public MultipleAreasAttribute(string area1, string area2, params string[] areaNames)
13+
{
14+
AreaNames = new string[] { area1, area2 }.Concat(areaNames).ToArray();
15+
}
16+
17+
public string[] AreaNames { get; }
18+
}
19+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Reflection;
7+
using Microsoft.AspNetCore.Mvc.ApplicationModels;
8+
9+
namespace ControllerForMultipleAreasSample
10+
{
11+
public class MultipleAreasControllerConvention : IApplicationModelConvention
12+
{
13+
public void Apply(ApplicationModel application)
14+
{
15+
var controllerModels = new List<ControllerModel>();
16+
foreach (var controller in application.Controllers)
17+
{
18+
var areaNames = controller.ControllerType.GetCustomAttributes<MultipleAreasAttribute>().FirstOrDefault()?.AreaNames;
19+
controller.RouteValues.Add("area", areaNames[0]);
20+
for (var i = 1; i < areaNames?.Length; i++)
21+
{
22+
var controllerCopy = new ControllerModel(controller);
23+
controllerCopy.RouteValues["area"] = areaNames[i];
24+
controllerModels.Add(controllerCopy);
25+
}
26+
}
27+
28+
foreach (var model in controllerModels)
29+
{
30+
application.Controllers.Add(model);
31+
}
32+
}
33+
}
34+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<Import Project="..\..\build\dependencies.props" />
4+
5+
<PropertyGroup>
6+
<IsPackable>false</IsPackable>
7+
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.AspNetCore" Version="$(AspNetCoreVersion)" />
12+
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="$(AspNetCoreVersion)" />
13+
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(AspNetCoreVersion)" />
14+
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(AspNetCoreVersion)" />
15+
</ItemGroup>
16+
17+
</Project>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.AspNetCore;
5+
using Microsoft.AspNetCore.Hosting;
6+
7+
namespace ControllerForMultipleAreasSample
8+
{
9+
public class Program
10+
{
11+
public static void Main(string[] args)
12+
{
13+
BuildWebHost(args).Run();
14+
}
15+
16+
public static IWebHost BuildWebHost(string[] args) =>
17+
WebHost.CreateDefaultBuilder(args)
18+
.UseStartup<Startup>()
19+
.Build();
20+
}
21+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Use the same Controller for multiple areas
2+
3+
This sample shows how to add a convention to MVC options (in `Startup`) that allows multiple areas to use the same Controller.
4+
5+
The `MultipleAreasControllerConvention` implements `IApplicationModelConvention`, and adds all the specified areas as `RouteValues` to the application model.
6+
7+
In this sample, Products, Services and Manage areas use the same `HomeController` to serve their Index view by listing the area names in the `MultipleAreasAttribute`.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.AspNetCore.Http;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace ControllerForMultipleAreasSample
7+
{
8+
public class Startup
9+
{
10+
public void ConfigureServices(IServiceCollection services)
11+
{
12+
services.AddMvc(options =>
13+
{
14+
options.Conventions.Add(new MultipleAreasControllerConvention());
15+
});
16+
}
17+
18+
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
19+
{
20+
if (env.IsDevelopment())
21+
{
22+
app.UseDeveloperExceptionPage();
23+
}
24+
25+
app.UseMvc(routes =>
26+
{
27+
routes.MapRoute(name: "areaRoute",
28+
template: "{area:exists}/{controller=Home}/{action=Index}");
29+
30+
routes.MapRoute(
31+
name: "default",
32+
template: "{controller=Home}/{action=Index}/{id?}");
33+
});
34+
35+
app.Run(async (context) =>
36+
{
37+
await context.Response.WriteAsync("Hello World!");
38+
});
39+
}
40+
}
41+
}

test/Entropy.FunctionalTests/Entropy.FunctionalTests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<ProjectReference Include="..\..\samples\Antiforgery.Angular1\Antiforgery.Angular1.csproj" />
3636
<ProjectReference Include="..\..\samples\Antiforgery.MvcWithAuthAndAjax\Antiforgery.MvcWithAuthAndAjax.csproj" />
3737
<ProjectReference Include="..\..\samples\Mvc.ActionConstraintSample.Web\Mvc.ActionConstraintSample.Web.csproj" />
38+
<ProjectReference Include="..\..\samples\Mvc.ControllerForMultipleAreasSample\Mvc.ControllerForMultipleAreasSample.csproj" />
3839
<ProjectReference Include="..\..\samples\Mvc.CustomRouteSample.Web\Mvc.CustomRouteSample.Web.csproj" />
3940
<ProjectReference Include="..\..\samples\Mvc.CustomRoutingConvention\Mvc.CustomRoutingConvention.csproj" />
4041
<ProjectReference Include="..\..\samples\Mvc.EmbeddedViewSample.Web\Mvc.EmbeddedViewSample.Web.csproj" />
@@ -49,6 +50,7 @@
4950
</ItemGroup>
5051

5152
<ItemGroup>
53+
<PackageReference Include="Microsoft.AspNetCore" Version="$(AspNetCoreVersion)" />
5254
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="$(AspNetCoreVersion)" />
5355
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(AspNetIntegrationTestingVersion)" />
5456
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="$(AspNetCoreVersion)" />
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Net;
5+
using System.Net.Http;
6+
using System.Threading.Tasks;
7+
using Microsoft.AspNetCore.Hosting;
8+
using Microsoft.AspNetCore.TestHost;
9+
using Microsoft.AspNetCore.Testing.xunit;
10+
using Xunit;
11+
12+
namespace Entropy.FunctionalTests
13+
{
14+
public class ControllerForMultipleAreasTest : IClassFixture<SampleTestFixture<ControllerForMultipleAreasSample.Startup>>
15+
{
16+
public ControllerForMultipleAreasTest(SampleTestFixture<ControllerForMultipleAreasSample.Startup> fixture)
17+
{
18+
Client = fixture.Client;
19+
}
20+
21+
public HttpClient Client { get; }
22+
23+
[Fact]
24+
public async Task ProductsArea()
25+
{
26+
// Arrange & Act
27+
var response = await Client.GetAsync("/Products/Home/Index");
28+
var content = await response.Content.ReadAsStringAsync();
29+
30+
// Assert
31+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
32+
Assert.Contains("Products View", content);
33+
}
34+
35+
[Fact]
36+
public async Task ServicesArea()
37+
{
38+
// Arrange & Act
39+
var response = await Client.GetAsync("/Services/Home/Index");
40+
var content = await response.Content.ReadAsStringAsync();
41+
42+
// Assert
43+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
44+
Assert.Contains("Services View", content);
45+
}
46+
47+
[Fact]
48+
public async Task ManageArea()
49+
{
50+
// Arrange & Act
51+
var response = await Client.GetAsync("/Manage/Home/Index");
52+
var content = await response.Content.ReadAsStringAsync();
53+
54+
// Assert
55+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
56+
Assert.Contains("Manage View", content);
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)