diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec index 9578ef96d9..8ec1484452 100644 --- a/build/NuSpecs/UmbracoCms.nuspec +++ b/build/NuSpecs/UmbracoCms.nuspec @@ -25,7 +25,7 @@ not want this to happen as the alpha of the next major is, really, the next major already. --> - + diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs index b7fd277ec7..f1f38504f1 100644 --- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs +++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs @@ -40,7 +40,7 @@ namespace Umbraco.Tests.Routing { base.SetUp(); - WebInitialComponent.CreateRoutes( + WebFinalComponent.CreateRoutes( new TestUmbracoContextAccessor(), TestObjects.GetGlobalSettings(), new SurfaceControllerTypeCollection(Enumerable.Empty()), diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 8cb9912890..8fb0dc6cd9 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -105,7 +105,7 @@ - 8.0.1 + 8.0.4 diff --git a/src/Umbraco.Web/Runtime/WebFinalComponent.cs b/src/Umbraco.Web/Runtime/WebFinalComponent.cs index 4673cc02e4..42ff0ee5e6 100644 --- a/src/Umbraco.Web/Runtime/WebFinalComponent.cs +++ b/src/Umbraco.Web/Runtime/WebFinalComponent.cs @@ -1,17 +1,130 @@ -using System.Web.Http; +using System; +using System.Linq; +using System.Web.Http; +using System.Web.Mvc; +using System.Web.Routing; +using Umbraco.Core; using Umbraco.Core.Composing; +using Umbraco.Core.Configuration; +using Umbraco.Web.Install; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; namespace Umbraco.Web.Runtime { public class WebFinalComponent : IComponent { + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly SurfaceControllerTypeCollection _surfaceControllerTypes; + private readonly UmbracoApiControllerTypeCollection _apiControllerTypes; + private readonly IGlobalSettings _globalSettings; + + public WebFinalComponent(IUmbracoContextAccessor umbracoContextAccessor, SurfaceControllerTypeCollection surfaceControllerTypes, UmbracoApiControllerTypeCollection apiControllerTypes, IGlobalSettings globalSettings) + { + _umbracoContextAccessor = umbracoContextAccessor; + _surfaceControllerTypes = surfaceControllerTypes; + _apiControllerTypes = apiControllerTypes; + _globalSettings = globalSettings; + } + public void Initialize() { + // set routes + CreateRoutes(_umbracoContextAccessor, _globalSettings, _surfaceControllerTypes, _apiControllerTypes); + // ensure WebAPI is initialized, after everything GlobalConfiguration.Configuration.EnsureInitialized(); } public void Terminate() { } + + // internal for tests + internal static void CreateRoutes( + IUmbracoContextAccessor umbracoContextAccessor, + IGlobalSettings globalSettings, + SurfaceControllerTypeCollection surfaceControllerTypes, + UmbracoApiControllerTypeCollection apiControllerTypes) + { + var umbracoPath = globalSettings.GetUmbracoMvcArea(); + + // create the front-end route + var defaultRoute = RouteTable.Routes.MapRoute( + "Umbraco_default", + umbracoPath + "/RenderMvc/{action}/{id}", + new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional } + ); + defaultRoute.RouteHandler = new RenderRouteHandler(umbracoContextAccessor, ControllerBuilder.Current.GetControllerFactory()); + + // register install routes + RouteTable.Routes.RegisterArea(); + + // register all back office routes + RouteTable.Routes.RegisterArea(new BackOfficeArea(globalSettings)); + + // plugin controllers must come first because the next route will catch many things + RoutePluginControllers(globalSettings, surfaceControllerTypes, apiControllerTypes); + } + + private static void RoutePluginControllers( + IGlobalSettings globalSettings, + SurfaceControllerTypeCollection surfaceControllerTypes, + UmbracoApiControllerTypeCollection apiControllerTypes) + { + var umbracoPath = globalSettings.GetUmbracoMvcArea(); + + // need to find the plugin controllers and route them + var pluginControllers = surfaceControllerTypes.Concat(apiControllerTypes).ToArray(); + + // local controllers do not contain the attribute + var localControllers = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace()); + foreach (var s in localControllers) + { + if (TypeHelper.IsTypeAssignableFrom(s)) + RouteLocalSurfaceController(s, umbracoPath); + else if (TypeHelper.IsTypeAssignableFrom(s)) + RouteLocalApiController(s, umbracoPath); + } + + // get the plugin controllers that are unique to each area (group by) + var pluginSurfaceControlleres = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace() == false); + var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName); + // loop through each area defined amongst the controllers + foreach (var g in groupedAreas) + { + // create & register an area for the controllers (this will throw an exception if all controllers are not in the same area) + var pluginControllerArea = new PluginControllerArea(globalSettings, g.Select(PluginController.GetMetadata)); + RouteTable.Routes.RegisterArea(pluginControllerArea); + } + } + + private static void RouteLocalApiController(Type controller, string umbracoPath) + { + var meta = PluginController.GetMetadata(controller); + var url = umbracoPath + (meta.IsBackOffice ? "/BackOffice" : "") + "/Api/" + meta.ControllerName + "/{action}/{id}"; + var route = RouteTable.Routes.MapHttpRoute( + $"umbraco-api-{meta.ControllerName}", + url, // url to match + new { controller = meta.ControllerName, id = UrlParameter.Optional }, + new[] { meta.ControllerNamespace }); + if (route.DataTokens == null) // web api routes don't set the data tokens object + route.DataTokens = new RouteValueDictionary(); + route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set + } + + private static void RouteLocalSurfaceController(Type controller, string umbracoPath) + { + var meta = PluginController.GetMetadata(controller); + var url = umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}"; + var route = RouteTable.Routes.MapRoute( + $"umbraco-surface-{meta.ControllerName}", + url, // url to match + new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional }, + new[] { meta.ControllerNamespace }); // look in this namespace to create the controller + route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "surface"); // ensure the umbraco token is set + route.DataTokens.Add("UseNamespaceFallback", false); // don't look anywhere else except this namespace! + // make it use our custom/special SurfaceMvcHandler + route.RouteHandler = new SurfaceRouteHandler(); + } } } diff --git a/src/Umbraco.Web/Runtime/WebInitialComponent.cs b/src/Umbraco.Web/Runtime/WebInitialComponent.cs index 3aaa8892eb..e1e0f4d80a 100644 --- a/src/Umbraco.Web/Runtime/WebInitialComponent.cs +++ b/src/Umbraco.Web/Runtime/WebInitialComponent.cs @@ -8,14 +8,12 @@ using System.Web.Configuration; using System.Web.Http; using System.Web.Http.Dispatcher; using System.Web.Mvc; -using System.Web.Routing; using ClientDependency.Core.CompositeFiles.Providers; using ClientDependency.Core.Config; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; using Umbraco.Core.IO; -using Umbraco.Web.Install; using Umbraco.Web.JavaScript; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; @@ -26,20 +24,10 @@ namespace Umbraco.Web.Runtime { public sealed class WebInitialComponent : IComponent { - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly SurfaceControllerTypeCollection _surfaceControllerTypes; - private readonly UmbracoApiControllerTypeCollection _apiControllerTypes; private readonly IGlobalSettings _globalSettings; - public WebInitialComponent( - IUmbracoContextAccessor umbracoContextAccessor, - SurfaceControllerTypeCollection surfaceControllerTypes, - UmbracoApiControllerTypeCollection apiControllerTypes, - IGlobalSettings globalSettings) + public WebInitialComponent(IGlobalSettings globalSettings) { - _umbracoContextAccessor = umbracoContextAccessor; - _surfaceControllerTypes = surfaceControllerTypes; - _apiControllerTypes = apiControllerTypes; _globalSettings = globalSettings; } @@ -63,9 +51,6 @@ namespace Umbraco.Web.Runtime // add global filters ConfigureGlobalFilters(); - - // set routes - CreateRoutes(_umbracoContextAccessor, _globalSettings, _surfaceControllerTypes, _apiControllerTypes); } public void Terminate() @@ -90,94 +75,6 @@ namespace Umbraco.Web.Runtime } } - // internal for tests - internal static void CreateRoutes( - IUmbracoContextAccessor umbracoContextAccessor, - IGlobalSettings globalSettings, - SurfaceControllerTypeCollection surfaceControllerTypes, - UmbracoApiControllerTypeCollection apiControllerTypes) - { - var umbracoPath = globalSettings.GetUmbracoMvcArea(); - - // create the front-end route - var defaultRoute = RouteTable.Routes.MapRoute( - "Umbraco_default", - umbracoPath + "/RenderMvc/{action}/{id}", - new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional } - ); - defaultRoute.RouteHandler = new RenderRouteHandler(umbracoContextAccessor, ControllerBuilder.Current.GetControllerFactory()); - - // register install routes - RouteTable.Routes.RegisterArea(); - - // register all back office routes - RouteTable.Routes.RegisterArea(new BackOfficeArea(globalSettings)); - - // plugin controllers must come first because the next route will catch many things - RoutePluginControllers(globalSettings, surfaceControllerTypes, apiControllerTypes); - } - - private static void RoutePluginControllers( - IGlobalSettings globalSettings, - SurfaceControllerTypeCollection surfaceControllerTypes, - UmbracoApiControllerTypeCollection apiControllerTypes) - { - var umbracoPath = globalSettings.GetUmbracoMvcArea(); - - // need to find the plugin controllers and route them - var pluginControllers = surfaceControllerTypes.Concat(apiControllerTypes).ToArray(); - - // local controllers do not contain the attribute - var localControllers = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace()); - foreach (var s in localControllers) - { - if (TypeHelper.IsTypeAssignableFrom(s)) - RouteLocalSurfaceController(s, umbracoPath); - else if (TypeHelper.IsTypeAssignableFrom(s)) - RouteLocalApiController(s, umbracoPath); - } - - // get the plugin controllers that are unique to each area (group by) - var pluginSurfaceControlleres = pluginControllers.Where(x => PluginController.GetMetadata(x).AreaName.IsNullOrWhiteSpace() == false); - var groupedAreas = pluginSurfaceControlleres.GroupBy(controller => PluginController.GetMetadata(controller).AreaName); - // loop through each area defined amongst the controllers - foreach (var g in groupedAreas) - { - // create & register an area for the controllers (this will throw an exception if all controllers are not in the same area) - var pluginControllerArea = new PluginControllerArea(globalSettings, g.Select(PluginController.GetMetadata)); - RouteTable.Routes.RegisterArea(pluginControllerArea); - } - } - - private static void RouteLocalApiController(Type controller, string umbracoPath) - { - var meta = PluginController.GetMetadata(controller); - var url = umbracoPath + (meta.IsBackOffice ? "/BackOffice" : "") + "/Api/" + meta.ControllerName + "/{action}/{id}"; - var route = RouteTable.Routes.MapHttpRoute( - $"umbraco-api-{meta.ControllerName}", - url, // url to match - new { controller = meta.ControllerName, id = UrlParameter.Optional }, - new[] { meta.ControllerNamespace }); - if (route.DataTokens == null) // web api routes don't set the data tokens object - route.DataTokens = new RouteValueDictionary(); - route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "api"); //ensure the umbraco token is set - } - - private static void RouteLocalSurfaceController(Type controller, string umbracoPath) - { - var meta = PluginController.GetMetadata(controller); - var url = umbracoPath + "/Surface/" + meta.ControllerName + "/{action}/{id}"; - var route = RouteTable.Routes.MapRoute( - $"umbraco-surface-{meta.ControllerName}", - url, // url to match - new { controller = meta.ControllerName, action = "Index", id = UrlParameter.Optional }, - new[] { meta.ControllerNamespace }); // look in this namespace to create the controller - route.DataTokens.Add(Core.Constants.Web.UmbracoDataToken, "surface"); // ensure the umbraco token is set - route.DataTokens.Add("UseNamespaceFallback", false); // don't look anywhere else except this namespace! - // make it use our custom/special SurfaceMvcHandler - route.RouteHandler = new SurfaceRouteHandler(); - } - private static void SetupMvcAndWebApi() { //don't output the MVC version header (security)