diff --git a/src/Umbraco.Tests.Integration/Umbraco.Web.Website/Routing/FrontEndRouteTests.cs b/src/Umbraco.Tests.Integration/Umbraco.Web.Website/Routing/FrontEndRouteTests.cs index e163990fe7..7a3fa7c853 100644 --- a/src/Umbraco.Tests.Integration/Umbraco.Web.Website/Routing/FrontEndRouteTests.cs +++ b/src/Umbraco.Tests.Integration/Umbraco.Web.Website/Routing/FrontEndRouteTests.cs @@ -1,5 +1,7 @@ +using System; using System.Net; using System.Net.Http; +using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using NUnit.Framework; @@ -10,7 +12,9 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Tests.Integration.TestServerTest; +using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Website.Controllers; +using Umbraco.Extensions; namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Routing { @@ -44,6 +48,24 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Routing // Assert Assert.AreEqual(HttpStatusCode.NoContent, response.StatusCode); } + + [Test] + public async Task Plugin_Controller_Routes_By_Area() + { + // Create URL manually, because PrepareSurfaceController URl will prepare whatever the controller is routed as + Type controllerType = typeof(TestPluginController); + var pluginAttribute = CustomAttributeExtensions.GetCustomAttribute(controllerType, false); + var controllerName = ControllerExtensions.GetControllerName(controllerType); + string url = $"/umbraco/{pluginAttribute?.AreaName}/{controllerName}"; + PrepareUrl(url); + + HttpResponseMessage response = await Client.GetAsync(url); + + string body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + + } } // Test controllers must be non-nested, else we need to jump through some hoops with custom @@ -61,4 +83,14 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Web.Website.Routing public IActionResult News() => NoContent(); } + + [PluginController("TestArea")] + public class TestPluginController : SurfaceController + { + public TestPluginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) + { + } + + public IActionResult Index() => Ok(); + } } diff --git a/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs b/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs index d1de1a2248..c7b8190523 100644 --- a/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/EndpointRouteBuilderExtensions.cs @@ -122,5 +122,27 @@ namespace Umbraco.Extensions true, constraints); } + + public static void MapUmbracoSurfaceRoute( + this IEndpointRouteBuilder endpoints, + Type controllerType, + string rootSegment, + string areaName, + string defaultAction = "Index", + bool includeControllerNameInRoute = true, + object constraints = null) + { + // If there is an area name it's a plugin controller, and we should use the area name instead of surface + string prefixPathSegment = areaName.IsNullOrWhiteSpace() ? "Surface" : areaName; + + endpoints.MapUmbracoRoute( + controllerType, + rootSegment, + areaName, + prefixPathSegment, + defaultAction, + includeControllerNameInRoute, + constraints); + } } } diff --git a/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs b/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs index 8f7fad9864..df25f4b66e 100644 --- a/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs +++ b/src/Umbraco.Web.Website/Routing/FrontEndRoutes.cs @@ -65,11 +65,10 @@ namespace Umbraco.Cms.Web.Website.Routing // exclude front-end api controllers PluginControllerMetadata meta = PluginController.GetMetadata(controller); - endpoints.MapUmbracoRoute( + endpoints.MapUmbracoSurfaceRoute( meta.ControllerType, _umbracoPathSegment, - meta.AreaName, - "Surface"); + meta.AreaName); } }