diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 74af8127d7..e89fa232da 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -768,6 +768,7 @@
+
diff --git a/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs b/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs
new file mode 100644
index 0000000000..7151dca828
--- /dev/null
+++ b/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Web.Http;
+using System.Web.Http.Controllers;
+using System.Web.Http.Dispatcher;
+
+namespace Umbraco.Web.WebApi
+{
+ public class NamespaceHttpControllerSelector : DefaultHttpControllerSelector
+ {
+ private const string ControllerKey = "controller";
+ private readonly HttpConfiguration _configuration;
+ private readonly Lazy> _duplicateControllerTypes;
+
+ public NamespaceHttpControllerSelector(HttpConfiguration configuration) : base(configuration)
+ {
+ _configuration = configuration;
+ _duplicateControllerTypes = new Lazy>(GetDuplicateControllerTypes);
+ }
+
+ public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
+ {
+ var routeData = request.GetRouteData();
+ if (routeData == null || routeData.Route == null || routeData.Route.DataTokens["Namespaces"] == null)
+ return base.SelectController(request);
+
+ // Look up controller in route data
+ object controllerName;
+ routeData.Values.TryGetValue(ControllerKey, out controllerName);
+ var controllerNameAsString = controllerName as string;
+ if (controllerNameAsString == null)
+ return base.SelectController(request);
+
+ //get the currently cached default controllers - this will not contain duplicate controllers found so if
+ // this controller is found in the underlying cache we don't need to do anything
+ var map = base.GetControllerMapping();
+ if (map.ContainsKey(controllerNameAsString))
+ return base.SelectController(request);
+
+ //the cache does not contain this controller because it's most likely a duplicate,
+ // so we need to sort this out ourselves and we can only do that if the namespace token
+ // is formatted correctly.
+ var namespaces = routeData.Route.DataTokens["Namespaces"] as IEnumerable;
+ if (namespaces == null)
+ return base.SelectController(request);
+
+ //see if this is in our cache
+ var found = _duplicateControllerTypes.Value
+ .Where(x => string.Equals(x.Name, controllerNameAsString + ControllerSuffix, StringComparison.OrdinalIgnoreCase))
+ .FirstOrDefault(x => namespaces.Contains(x.Namespace));
+
+ if (found == null)
+ return base.SelectController(request);
+
+ return new HttpControllerDescriptor(_configuration, controllerNameAsString, found);
+ }
+
+ private IEnumerable GetDuplicateControllerTypes()
+ {
+ var assembliesResolver = _configuration.Services.GetAssembliesResolver();
+ var controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
+ var controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
+
+ //we have all controller types, so just store the ones with duplicate class names - we don't
+ // want to cache too much and the underlying selector caches everything else
+
+ var duplicates = controllerTypes.GroupBy(x => x.Name)
+ .Where(x => x.Count() > 1)
+ .SelectMany(x => x);
+
+ return duplicates;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs
index c04d5acf69..88a44242dc 100644
--- a/src/Umbraco.Web/WebBootManager.cs
+++ b/src/Umbraco.Web/WebBootManager.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.Http;
+using System.Web.Http.Dispatcher;
using System.Web.Mvc;
using System.Web.Routing;
using ClientDependency.Core.Config;
@@ -339,6 +340,9 @@ namespace Umbraco.Web
new PublishedCache.XmlPublishedCache.PublishedContentCache(),
new PublishedCache.XmlPublishedCache.PublishedMediaCache()));
+ GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),
+ new NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));
+
FilteredControllerFactoriesResolver.Current = new FilteredControllerFactoriesResolver(
// add all known factories, devs can then modify this list on application
// startup either by binding to events or in their own global.asax