back to Jitbit Blog home About this blog

Fastest way to generate URLs in an ASP.NET MVC app

by Alex Yumashev · Updated Apr 18 2022

Almost any "optimize ASP.NET for best speed" tutorial out there suggests optimizing the URL-generation process in some way. You know, getting rid of those Url.Action("Action", "Controller") calls that are expression-tree based, replacing them with RouteUrl, or implementing some route-resolution caching etc etc..

Including this great blog post by Sam Saffron, or this epic presentation by Rudi Benkovic, or this great discussion at StackOverflow.

And almost no tutorial mentions that the best way to generate URLs is... to not generate them at all. If your app's URL sctructure is more or less simple (follows the basic {controller}/{action}/{id} pattern for example), why not simply use Url.Content("~/Blahblah/Blah/")?

I've ran some tests. 2000 (two thousand) iterations of URL-generation using various methods suggested by these blog-posts. Here are the results:

Code: Url.Action('ActionName', 'ControllerName', new { id = x })
Milliseconds: 38

OK, this one does not use any optimization hacks whatsoever.

Code: Url.Action("ActionName", "ControllerName", new RouteValueDictionary { { "id", x } })
Milliseconds: 23

That's better! We removed the overhead that converts an anonymous type to a RouteValueCollection (using "PropertyDescriptors" and shit).

Code: Url.RouteUrl("Default", new RouteValueDictionary { { "Controller", "ControllerName" },
{ "Action", "ActionName" }, { "id", x } }

Milliseconds:18

Even better! We removed the expression-tree bases lookup of a route, instead specifying the route-name explicitly. This is considered to be the fastest way of generating an URL without involving some caching mechanism.

Code: Url.Content("~/ControllerName/ActionName/" + x);
Milliseconds:1

Plain old static string. Beats the third option by 18 times. And it's 36 times faster than the original "Url.Action". Just think about it. 36 times! The downside is that your URL routes are not all controlled in one place any more. So it will fit only if your app uses the simplest "controller/action/id" pattern or something like it.

Also, I wouldn't recommend replacing ALL your URL-generating code with this, just find the most accessed views and consider changing the Url.Action calls inside big "foreach" loops or something, this way your changes will have impact, otherwise don't bother.

Update for .NET Core:

Testing under .NET 5 and 6 confirmed the case, I pretty much get the same results. Url.Action is slow. What's even more interesting, using "tag helpers" like <a href="~/path/to"> performs very badly compared to @Url.Content(). I filed an issue to Microsoft but they confirmed this is by design. Do not use tag helpers.