Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ASP.NET-MVC Routing's UrlParameter.Optional ignored when using this Regex?

This is a stripped down example of a problem I was having this morning with ASP.NET MVC's URL routing.

Fairly simple, I wanted a route's Action to be called, whether or not the parameter on the end was supplied.

This route works fine, matching both /apple/ and /apple/test/

routes.MapRoute(
    "Working Route",
    "apple/{parameter}",
    new { 
        controller = "Apple", 
        action = "Action", 
        parameter = UrlParameter.Optional
    },
    new { parameter = @"([a-z0-9\.-]+)" }
);

However, this second route will only match /banana/test/ and the like. When I try /banana/, the router just passes right over it and returns the catch-all 404 error.

routes.MapRoute(
    "Non-Working Route",
    "banana/{parameter}",
    new { 
        controller = "Banana", 
        action = "Action", 
        parameter = UrlParameter.Optional
    },
    new { parameter = @"([a-z0-9]+)" }
);

The only difference is the Regex validation of the parameter, but as it's quite a simple Regex match, they should both work perfectly fine for a URL like /banana/, yet the second route just fails to recognise it.

I side-stepped my problem by just changing the Regex on route #2 to match that on route #1, and accept the '.' and '-' characters, I just wondered if anyone knows why this seems to be happening.

EDIT:

Here are the Controllers and Actions that I'm using for my example. Nothing fancy here.

public class AppleController : Controller
{
    public ActionResult Action(string parameter)
    {
        if (parameter == null)
        {
            parameter = "No parameter specified.";
        }
        ViewData["parameter"] = parameter;
        return View();
    }
}

public class BananaController : Controller
{
    public ActionResult Action(string parameter)
    {
        if (parameter == null)
        {
            parameter = "No parameter specified.";
        }
        ViewData["parameter"] = parameter;
        return View();
    }
}

So my problem is that /apple/ would display "No parameter specified.", while /banana/ gives me an undesired 404 instead.


So far..

Using parameter = URLParameter.Optional in the Route declaration: Route #1 works perfectly, Route #2 doesn't match without the parameter.

Using parameter = "" in the Route declaration: Both Route #1 & Route #2 fail to match when the parameter is left off the URL.

Declaring parameter = "" in the Action method signature: Not possible due to .NET version.

Removing all other routes has no effect.

like image 741
Ben Jenkinson Avatar asked Oct 12 '22 16:10

Ben Jenkinson


1 Answers

If the token is optional then whatever regex constraint you use must also reflect that, e.g. (foo)?.


I was able to reproduce this issue with ASP.NET MVC 2 on .NET 4 . Then I upgraded to ASP.NET MVC 3 and everything worked as expected. The solution I present above does not work with ASP.NET MVC 2, but it works with ASP.NET MVC 3, so I can only assume this is a bug on v2 that is now fixed in v3.

You can reference v2, and use this on web.config to test with v3:

<runtime>
   <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
         <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
         <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
   </assemblyBinding>
</runtime>
like image 75
Max Toro Avatar answered Oct 20 '22 16:10

Max Toro