Gotcha in Orchard CMS RoutesDescriptor when using Multi-Tenancy
It's been a while since I posted, and I've been using Orchard CMS a lot among other things. I came across a rather trickysome problem today, hopefully this post will help others find the resolution quicker than I did. In orchard you can Implement IRouteProvider in any module you write. This is basically a wrapper for MVC routes, and works really well. For example, the route defined below is for custom handling in the event of errors.
public class ErrorHandlingRoutesProvider : IRouteProvider { public IEnumerable<routedescriptor> GetRoutes() { return new[]{
new RouteDescriptor{ Name = "ErrorRoute",
Priority = 1,
Route = new Route( "Error", new RouteValueDictionary{ {"action", "ErrorPage"}, {"controller", "ErrorHandler"}, {"area", "BG.Shared.ErrorHandling"} }, new RouteValueDictionary(),//constraints (none here) new RouteValueDictionary{ {"area", "BG.Shared.ErrorHandling"} }, new MvcRouteHandler()) }; }
This works as intended in a single site. However, when you have two tenants using the same module, this will fail with an error similar to the following:
System.ArgumentException: A route named 'ErrorRoute' is already in the route collection. Route names must be unique. Parameter name: name at System.Web.Routing.RouteCollection.Add(String name, RouteBase item) at Orchard.Mvc.Routes.RoutePublisher.Publish(IEnumerable`1 routes) in d:\Workspaces\GitHub\src\Orchard\Mvc\Routes\RoutePublisher.cs:line 100 at Orchard.Environment.DefaultOrchardShell.Activate() in d:\Workspaces\GitHub\src\Orchard\Environment\DefaultOrchardShell.cs:line 48 at Orchard.Environment.DefaultOrchardHost.ActivateShell(ShellContext context) in d:\Workspaces\GitHub\src\Orchard\Environment\DefaultOrchardHost.cs:line 156 at Orchard.Environment.DefaultOrchardHost.CreateAndActivateShells() in d:\Workspaces\GitHub\src\Orchard\Environment\DefaultOrchardHost.cs:line 135
The workaround is to comment out the "Name" attribute of the RouteDescriptor, as follows
public IEnumerable<RouteDescriptor> GetRoutes() { return new[]{
new RouteDescriptor{<span style="color: green;">//Name = "ErrorRoute", //This doesn't work in Multi-Tenancy</span> Priority = <span style="color: maroon;">1</span>, Route = <span style="color: blue;">new</span> Route( <span style="color: maroon;">"Error"</span>, <span style="color: blue;">new</span> RouteValueDictionary{ {<span style="color: maroon;">"action"</span>, <span style="color: maroon;">"ErrorPage"</span>}, {<span style="color: maroon;">"controller"</span>, <span style="color: maroon;">"ErrorHandler"</span>}, {<span style="color: maroon;">"area"</span>, <span style="color: maroon;">"BG.Shared.ErrorHandling"</span>} }, <span style="color: blue;">new</span> RouteValueDictionary(),<span style="color: green;">//constraints (none here)</span> <span style="color: blue;">new</span> RouteValueDictionary{ {<span style="color: maroon;">"area"</span>, <span style="color: maroon;">"BG.Shared.ErrorHandling"</span>} }, <span style="color: blue;">new</span> MvcRouteHandler()) } }; }</pre>I've started investigating this with the Orchard team, but the workaround doesn't really appear to have any drawbacks.