U4-2518 - Virtual directory named 'Umbraco' will cause the route engine to fail

Created by Aaron Powell 17 Jul 2013, 03:43:57 Updated by Stephan 06 Mar 2014, 07:21:37

If you put Umbraco inside a Virtual Directory named Umbraco it will fail with the following exception:

Server Error in '/Umbraco' Application.

The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character. Parameter name: routeUrl

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentException: The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character. Parameter name: routeUrl

Source Error:

Line 149: Line 150: //Create the front-end route Line 151: var defaultRoute = RouteTable.Routes.MapRoute( Line 152: "Umbraco_default", Line 153: umbracoPath + "/RenderMvc//",

Source File: c:_Projects\github\Umbraco-CMS\src\Umbraco.Web\WebBootManager.cs Line: 151

Stack Trace:

[ArgumentException: The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character. Parameter name: routeUrl] System.Web.Routing.RouteParser.Parse(String routeUrl) +3712821 System.Web.Routing.Route..ctor(String url, IRouteHandler routeHandler) +28 System.Web.Mvc.RouteCollectionExtensions.MapRoute(RouteCollection routes, String name, String url, Object defaults, Object constraints, String[] namespaces) +90 System.Web.Mvc.RouteCollectionExtensions.MapRoute(RouteCollection routes, String name, String url, Object defaults, Object constraints) +28 System.Web.Mvc.RouteCollectionExtensions.MapRoute(RouteCollection routes, String name, String url, Object defaults) +18 Umbraco.Web.WebBootManager.CreateRoutes() in c:_Projects\github\Umbraco-CMS\src\Umbraco.Web\WebBootManager.cs:151 Umbraco.Web.WebBootManager.Complete(Action`1 afterComplete) in c:_Projects\github\Umbraco-CMS\src\Umbraco.Web\WebBootManager.cs:133 Umbraco.Core.UmbracoApplicationBase.StartApplication(Object sender, EventArgs e) in c:_Projects\github\Umbraco-CMS\src\Umbraco.Core\UmbracoApplicationBase.cs:39 Umbraco.Core.UmbracoApplicationBase.Application_Start(Object sender, EventArgs e) in c:_Projects\github\Umbraco-CMS\src\Umbraco.Core\UmbracoApplicationBase.cs:52

[HttpException (0x80004005): The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character. Parameter name: routeUrl] System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +12578701 System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +175 System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +304 System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +404 System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +475

[HttpException (0x80004005): The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character. Parameter name: routeUrl] System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +12550448 System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +159 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +12343997

Changing the virtual directory name to say cms is fine though.

Env:

  • Win8
  • IIS8
  • Umbraco 6.1.2 (installed via NuGet into a WebApp project)

Comments

Aaron Powell 17 Jul 2013, 04:01:18

So I did some investigation into why this happens (and decided to put it into a comment rather than have it lost in the huge stacktrace :P). The reason this happens is because the value that it's trying to insert into the route table is "/RenderMvc//". This isn't valid, MVC routes can't start with a "/" (or the other characters listed).

That brings me to the next question, why is the "umbracoPath" value not being respected? Well that turns out to be because it's an empty string. Since this comes from the GlobalSettings.UmbracoMvcArea I dug a bit deeper to work out why the settings property was returning an empty string. Well that happens because of a series of fun:

  • Path is "/Umbraco/umbraco", being the combination of the virtual directory and umbracoPath
  • The Path then has TrimStart called on it with the SystemDirectories.Root provided, which happens to match "/Umbraco"
  • This results in an empty string

Now, I believe the actual root of this problem is in the TrimStart method, it doesn't trim the start, it removes all instances ''which isn't what the CLR TrimStart method does''. See [this gist here|https://gist.github.com/aaronpowell/1fe6a0bfbdb9f69e43d2], it calls the CLR TrimStart and the Umbraco implementation and they result in different end values.

So, what to fix?

I think that the TrimStart method is the one that should be fixed primarily because it's an inconsistent implementation compared to the CLR, and really is it even needed? Is converting a string to a char array ''that'' much of an overhead that an extension method is required? (I've done the change but NUnit keeps crashing so I haven't sent a PR)


Stephan 23 Sep 2013, 09:16:14

I'd say it's an issue with TrimStart indeed. Will have a look.


Stephan 01 Nov 2013, 08:42:22

When you do path.TrimStart("/Umbraco".ToCharArray()) it does not do what you seem to imply: it does not trim the string "/Umbraco", but it trims the string as long a starting character is one of those contained in "/Umbraco". It ''seems'' to work in your Git because your string is "/Umbraco/umbraco"... but in fact the slash is also removed:

[Test] public void TrimStart() { var path = "/Umbraco/umbraco"; var toTrim = "/Umbraco"; var trimmed = path.TrimStart(toTrim.ToCharArray()); Assert.AreEqual("umbraco", trimmed); // note: slash is gone! }

So Umbraco's implementation of TrimStart is compliant with the Framework's implementation. That being said, using TrimStart here might be the error. Looking into it.


Stephan 01 Nov 2013, 08:54:37

Pushed commit 2671709 in 6.2.0 that should fix it. Can you test?


Shannon Deminick 06 Mar 2014, 01:31:35

Stephen, can you mark this as fixed if it is complete?


Priority: Normal

Type: Bug

State: Fixed

Assignee:

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted:

Affected versions:

Due in version: 7.1.0, 6.2.0

Sprint:

Story Points:

Cycle: