First call to Url.Action on a page is slow

Problem found, and it is with the routing tables (cheers Kirill).

Basically we have lots of routes that look something like this:

string[] controllers = GetListOfValidControllers();

routes.MapRoute(
    name: GetRouteName(),
    url: subfolder + "/{controller}/{action}/{id}",
    defaults: new { action = "Index", id = UrlParameter.Optional },
    constraints: new { controller = "(" + string.Join("|", controllers) + ")" });

It turns out that the Regex check is very slow, painfully slow. So I replaced it with an implementation of IRouteConstraint that just checks against a HashSet instead.

Then I changed the map route call:

routes.MapRoute(
    name: GetRouteName(),
    url: subfolder + "/{controller}/{action}/{id}",
    defaults: new { action = "Index", id = UrlParameter.Optional },
    constraints: new { controller = new HashSetConstraint(controllers) });

I also used the RegexConstraint mentioned in that linked article for anything more complicated - including lots of calls like this (because we have legacy WebForm pages):

routes.IgnoreRoute(
    url: "{*allaspx}", 
    constraints: new { allaspx = new RegexConstraint( @".*\.as[pmh]x(/.*)?") });

Those two simple changes completely fix the problem; Url.Action and Html.BeginForm now take a negligible amount of time (even with lots of routes).