diff --git a/src/Orchard/Mvc/Routes/HubRoute.cs b/src/Orchard/Mvc/Routes/HubRoute.cs new file mode 100644 index 000000000..6bef2b7ee --- /dev/null +++ b/src/Orchard/Mvc/Routes/HubRoute.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using Orchard.Environment; +using Orchard.Environment.Configuration; + +namespace Orchard.Mvc.Routes { + + public class HubRoute : RouteBase, IRouteWithArea, IComparable { + private readonly IRunningShellTable _runningShellTable; + + private readonly ConcurrentDictionary> _routesByShell = new ConcurrentDictionary>(); + + public HubRoute(string area, int priority, IRunningShellTable runningShellTable) { + Priority = priority; + Area = area; + _runningShellTable = runningShellTable; + } + + public string Area { get; private set; } + public int Priority { get; private set; } + + /// + /// Removes the routes associated with a shell + /// + public void ReleaseShell(ShellSettings shellSettings) { + IList routes; + _routesByShell.TryRemove(shellSettings.Name, out routes); + } + + public void Add(RouteBase route, ShellSettings shellSettings) { + var routes = _routesByShell.GetOrAdd(shellSettings.Name, key => new List()); + routes.Add(route); + } + + public override RouteData GetRouteData(HttpContextBase httpContext) { + var settings = _runningShellTable.Match(httpContext); + + if (settings == null) + return null; + + IList routes; + if (!_routesByShell.TryGetValue(settings.Name, out routes)) { + return null; + } + + foreach (var route in routes) { + RouteData routeData = route.GetRouteData(httpContext); + if(routeData != null) { + return routeData; + } + } + + return null; + } + + public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { + var settings = _runningShellTable.Match(requestContext.HttpContext); + + if (settings == null) + return null; + + IList routes; + if (!_routesByShell.TryGetValue(settings.Name, out routes)) { + return null; + } + + foreach (var route in routes) { + VirtualPathData virtualPathData = route.GetVirtualPath(requestContext, values); + if (virtualPathData != null) { + return virtualPathData; + } + } + + return null; + } + + public int CompareTo(HubRoute other) { + if (other == null) { + return -1; + } + + if (other == this) { + return 0; + } + + if (!String.Equals(other.Area, Area, StringComparison.OrdinalIgnoreCase)) { + return StringComparer.OrdinalIgnoreCase.Compare(other.Area, Area); + } + + if (other.Priority == Priority) { + return StringComparer.OrdinalIgnoreCase.Compare(other.Area, Area); + } + + return Priority.CompareTo(other.Priority); + } + } +} diff --git a/src/Orchard/Mvc/Routes/RoutePublisher.cs b/src/Orchard/Mvc/Routes/RoutePublisher.cs index b8344ed66..cf3859910 100644 --- a/src/Orchard/Mvc/Routes/RoutePublisher.cs +++ b/src/Orchard/Mvc/Routes/RoutePublisher.cs @@ -5,6 +5,7 @@ using System.Web.Http; using System.Web.Mvc; using System.Web.Routing; using System.Web.SessionState; +using Castle.Core; using Orchard.Environment; using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; @@ -55,14 +56,9 @@ namespace Orchard.Mvc.Routes { using (_routeCollection.GetWriteLock()) { // existing routes are removed while the collection is briefly inaccessable - var cropArray = _routeCollection - .OfType() - .Where(sr => sr.ShellSettingsName == _shellSettings.Name) - .ToArray(); - - foreach(var crop in cropArray) { - _routeCollection.Remove(crop); - } + _routeCollection + .OfType() + .ForEach(x => x.ReleaseShell(_shellSettings)); // new routes are added foreach (var routeDescriptor in routesArray) { @@ -98,14 +94,35 @@ namespace Orchard.Mvc.Routes { SessionState = sessionStateBehavior }; - try { - _routeCollection.Add(routeDescriptor.Name, shellRoute); - } - catch(ArgumentException) { - // Named routes can be added multiple times in the case of a module - // loaded in multiple tenants. There is no way to ensure a named route - // is already registered, thus catching the specific exception. + var area = extensionDescriptor == null ? "" : extensionDescriptor.Id; + + var matchedHubRoute = _routeCollection.FirstOrDefault(x => { + var hubRoute = x as HubRoute; + if (hubRoute == null) { + return false; + } + + return routeDescriptor.Priority == hubRoute.Priority && hubRoute.Area.Equals(area, StringComparison.OrdinalIgnoreCase); + }) as HubRoute; + + if (matchedHubRoute == null) { + matchedHubRoute = new HubRoute(area, routeDescriptor.Priority, _runningShellTable); + + int index; + for (index = 0; index < _routeCollection.Count; index++) { + var hubRoute = _routeCollection[index] as HubRoute; + if (hubRoute == null) { + continue; + } + if (hubRoute.Priority < matchedHubRoute.Priority) { + break; + } + } + + _routeCollection.Insert(index, matchedHubRoute); } + + matchedHubRoute.Add(shellRoute, _shellSettings); } } } diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 07be474dd..2a8b2c1e0 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -275,6 +275,7 @@ +