I have a performance issue with a fairly simple ASP.MVC view.
It's a log-on page that should be almost instant, but is taking about half a second.
After a lot of digging it looks like the problem is the first call the Url.Action
- it's taking around 450ms (according to MiniProfiler) but that seems insanely slow.
Subsequent calls to Url.Action
are taking <1ms, which is more in line with what I would expect.
This is consistent whether I use Url.Action("action", "controller")
or Url.Action("action")
, but doesn't seem to happen if I use Url.Content("~/controller/action")
. This also happens when I call Html.BeginForm("action")
.
Does anyone have any idea what's causing this?
A dig into the source suggests that RouteCollection.GetVirtualPath
might be the culprit, as that's common to both Url.Action
and Html.BeginForm
. However, surely that's used all over the place? I mean, ½ a second is far too slow.
I have 20 or so custom routes (it's a fairly large app with some legacy WebForms pages) but even then the times seem far too slow.
Any ideas how to fix it?
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With