diff --git a/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs b/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs index dd75decc11..1447085dc2 100644 --- a/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs +++ b/src/Umbraco.Web/WebApi/NamespaceHttpControllerSelector.cs @@ -14,12 +14,12 @@ namespace Umbraco.Web.WebApi { private const string ControllerKey = "controller"; private readonly HttpConfiguration _configuration; - private readonly Lazy> _duplicateControllerTypes; + private readonly Lazy> _duplicateControllerTypes; public NamespaceHttpControllerSelector(HttpConfiguration configuration) : base(configuration) { _configuration = configuration; - _duplicateControllerTypes = new Lazy>(GetDuplicateControllerTypes); + _duplicateControllerTypes = new Lazy>(GetDuplicateControllerTypes); } public override HttpControllerDescriptor SelectController(HttpRequestMessage request) @@ -52,32 +52,69 @@ namespace Umbraco.Web.WebApi 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)); - + var found = _duplicateControllerTypes.Value.FirstOrDefault(x => string.Equals(x.ControllerName, controllerNameAsString, StringComparison.OrdinalIgnoreCase) && namespaces.Contains(x.ControllerNamespace)); if (found == null) return base.SelectController(request); - return new HttpControllerDescriptor(_configuration, controllerNameAsString, found); + return found.Descriptor; } - private IEnumerable GetDuplicateControllerTypes() + private ConcurrentStack 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 groupedByName = controllerTypes.GroupBy( + t => t.Name.Substring(0, t.Name.Length - ControllerSuffix.Length), + StringComparer.OrdinalIgnoreCase).Where(x => x.Count() > 1); - var duplicates = controllerTypes.GroupBy(x => x.Name) - .Where(x => x.Count() > 1) - .SelectMany(x => x) - .ToArray(); + var duplicateControllers = groupedByName.ToDictionary( + g => g.Key, + g => g.ToLookup(t => t.Namespace ?? String.Empty, StringComparer.OrdinalIgnoreCase), + StringComparer.OrdinalIgnoreCase); - return duplicates; + var result = new ConcurrentStack(); + + foreach (var controllerTypeGroup in duplicateControllers) + { + foreach (var controllerType in controllerTypeGroup.Value.SelectMany(controllerTypesGrouping => controllerTypesGrouping)) + { + result.Push(new NamespaceHttpControllerMetadata(controllerTypeGroup.Key, controllerType.Namespace, + new HttpControllerDescriptor(_configuration, controllerTypeGroup.Key, controllerType))); + } + } + + return result; + } + + private class NamespaceHttpControllerMetadata + { + private readonly string _controllerName; + private readonly string _controllerNamespace; + private readonly HttpControllerDescriptor _descriptor; + + public NamespaceHttpControllerMetadata(string controllerName, string controllerNamespace, HttpControllerDescriptor descriptor) + { + _controllerName = controllerName; + _controllerNamespace = controllerNamespace; + _descriptor = descriptor; + } + + public string ControllerName + { + get { return _controllerName; } + } + + public string ControllerNamespace + { + get { return _controllerNamespace; } + } + + public HttpControllerDescriptor Descriptor + { + get { return _descriptor; } + } } - } } \ No newline at end of file