From c8e20cf64b7064bfa06c4ddf0d70abd6afe2793c Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Thu, 28 Mar 2013 09:07:36 +0600 Subject: [PATCH] Fixes: #U4-2012, #U4-2005 --- .../Mvc/AreaRegistrationExtensions.cs | 150 ++++++++++-------- src/Umbraco.Web/Mvc/ControllerExtensions.cs | 4 + src/Umbraco.Web/Mvc/PluginControllerArea.cs | 2 +- 3 files changed, 92 insertions(+), 64 deletions(-) diff --git a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs index cb905c3569..b67d73880e 100644 --- a/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs +++ b/src/Umbraco.Web/Mvc/AreaRegistrationExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; using Umbraco.Core; @@ -8,73 +9,96 @@ using Umbraco.Core.Configuration; namespace Umbraco.Web.Mvc { internal static class AreaRegistrationExtensions - { - /// - /// Creates a custom individual route for the specified controller plugin. Individual routes - /// are required by controller plugins to map to a unique URL based on ID. - /// - /// - /// - /// An existing route collection - /// - /// The suffix name that the controller name must end in before the "Controller" string for example: - /// ContentTreeController has a controllerSuffixName of "Tree", this is used for route constraints. - /// - /// - /// - /// - /// The DataToken value to set for the 'umbraco' key, this defaults to 'backoffice' + { + /// + /// Creates a custom individual route for the specified controller plugin. Individual routes + /// are required by controller plugins to map to a unique URL based on ID. + /// + /// + /// + /// An existing route collection + /// + /// The suffix name that the controller name must end in before the "Controller" string for example: + /// ContentTreeController has a controllerSuffixName of "Tree", this is used for route constraints. + /// + /// + /// + /// + /// The DataToken value to set for the 'umbraco' key, this defaults to 'backoffice' /// By default this value is just {action}/{id} but can be modified for things like web api routes - /// - /// - internal static Route RouteControllerPlugin(this AreaRegistration area, string controllerName, Type controllerType, RouteCollection routes, - string controllerSuffixName, string defaultAction, object defaultId, - string umbracoTokenValue = "backoffice", - string routeTokens = "{action}/{id}") - { - Mandate.ParameterNotNullOrEmpty(controllerName, "controllerName"); - Mandate.ParameterNotNullOrEmpty(controllerSuffixName, "controllerSuffixName"); - Mandate.ParameterNotNullOrEmpty(defaultAction, "defaultAction"); - Mandate.ParameterNotNull(controllerType, "controllerType"); - Mandate.ParameterNotNull(routes, "routes"); - Mandate.ParameterNotNull(defaultId, "defaultId"); + /// Default is true for MVC, otherwise false for WebAPI + /// + /// + internal static Route RouteControllerPlugin(this AreaRegistration area, string controllerName, Type controllerType, RouteCollection routes, + string controllerSuffixName, string defaultAction, object defaultId, + string umbracoTokenValue = "backoffice", + string routeTokens = "{action}/{id}", + bool isMvc = true) + { + Mandate.ParameterNotNullOrEmpty(controllerName, "controllerName"); + Mandate.ParameterNotNullOrEmpty(controllerSuffixName, "controllerSuffixName"); + + Mandate.ParameterNotNull(controllerType, "controllerType"); + Mandate.ParameterNotNull(routes, "routes"); + Mandate.ParameterNotNull(defaultId, "defaultId"); - var umbracoArea = GlobalSettings.UmbracoMvcArea; + var umbracoArea = GlobalSettings.UmbracoMvcArea; - //routes are explicitly name with controller names and IDs - var url = umbracoArea + "/" + area.AreaName + "/" + controllerName + "/" + routeTokens; + //routes are explicitly name with controller names and IDs + var url = umbracoArea + "/" + area.AreaName + "/" + controllerName + "/" + routeTokens; - //create a new route with custom name, specified url, and the namespace of the controller plugin - var controllerPluginRoute = routes.MapRoute( - //name - string.Format("umbraco-{0}", controllerType.FullName), - //url format - url, - //set the namespace of the controller to match - new[] { controllerType.Namespace }); - - //set defaults - controllerPluginRoute.Defaults = new RouteValueDictionary( - new Dictionary - { - { "controller", controllerName }, - { "action", defaultAction }, - { "id", defaultId } - }); + Route controllerPluginRoute; + //var meta = PluginController.GetMetadata(controllerType); + if (isMvc) + { + //create a new route with custom name, specified url, and the namespace of the controller plugin + controllerPluginRoute = routes.MapRoute( + //name + string.Format("umbraco-{0}", controllerType.FullName), + //url format + url, + //set the namespace of the controller to match + new[] {controllerType.Namespace}); - //constraints: only match controllers ending with 'controllerSuffixName' and only match this controller's ID for this route - controllerPluginRoute.Constraints = new RouteValueDictionary( - new Dictionary - { - { "controller", @"(\w+)" + controllerSuffixName } - }); - - - //match this area - controllerPluginRoute.DataTokens.Add("area", area.AreaName); - controllerPluginRoute.DataTokens.Add("umbraco", umbracoTokenValue); //ensure the umbraco token is set + //set defaults + controllerPluginRoute.Defaults = new RouteValueDictionary( + new Dictionary + { + {"controller", controllerName}, + {"action", defaultAction}, + {"id", defaultId} + }); + } + else + { + controllerPluginRoute = routes.MapHttpRoute( + //name + string.Format("umbraco-{0}-{1}", "api", controllerType.FullName), + //url format + url, + new { controller = controllerName, id = defaultId }); + //web api routes don't set the data tokens object + if (controllerPluginRoute.DataTokens == null) + { + controllerPluginRoute.DataTokens = new RouteValueDictionary(); + } + //look in this namespace to create the controller + controllerPluginRoute.DataTokens.Add("Namespaces", controllerType.Namespace); + } - return controllerPluginRoute; - } - } + //constraints: only match controllers ending with 'controllerSuffixName' and only match this controller's ID for this route + controllerPluginRoute.Constraints = new RouteValueDictionary( + new Dictionary + { + {"controller", @"(\w+)" + controllerSuffixName} + }); + + + //match this area + controllerPluginRoute.DataTokens.Add("area", area.AreaName); + controllerPluginRoute.DataTokens.Add("umbraco", umbracoTokenValue); //ensure the umbraco token is set + + return controllerPluginRoute; + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Mvc/ControllerExtensions.cs b/src/Umbraco.Web/Mvc/ControllerExtensions.cs index 0e383add83..d17b1f2afe 100644 --- a/src/Umbraco.Web/Mvc/ControllerExtensions.cs +++ b/src/Umbraco.Web/Mvc/ControllerExtensions.cs @@ -14,6 +14,10 @@ namespace Umbraco.Web.Mvc /// internal static string GetControllerName(Type controllerType) { + if (!controllerType.Name.EndsWith("Controller")) + { + throw new InvalidOperationException("The controller type " + controllerType + " does not follow conventions, MVC Controller class names must be suffixed with the term 'Controller'"); + } return controllerType.Name.Substring(0, controllerType.Name.LastIndexOf("Controller")); } diff --git a/src/Umbraco.Web/Mvc/PluginControllerArea.cs b/src/Umbraco.Web/Mvc/PluginControllerArea.cs index 25472a2ffa..0e34e2cdef 100644 --- a/src/Umbraco.Web/Mvc/PluginControllerArea.cs +++ b/src/Umbraco.Web/Mvc/PluginControllerArea.cs @@ -85,7 +85,7 @@ namespace Umbraco.Web.Mvc { foreach (var s in apiControllers) { - this.RouteControllerPlugin(s.ControllerName, s.ControllerType, routes, "Api", "Index", UrlParameter.Optional, "api"); + this.RouteControllerPlugin(s.ControllerName, s.ControllerType, routes, "Api", "", UrlParameter.Optional, "api", isMvc: false); } } }