budi
budi

Reputation: 6551

Is UrlHelper.Action Equivalent to UrlHelper.RouteUrl?

I want to replace all instances of UrlHelper.Action with UrlHelper.RouteUrl in my code because of the performance benefits. According to the documentation, both methods will generate a fully qualified URL, I want to confirm that they will return the exact same URL.


Example:

Assuming that the routes in RouteConfig have unique controller, action combinations:

Given the following route in RouteConfig:

routes.MapRoute(
    "RouteName",
    "Url",
    new { controller = "Controller", action = "Action" }
);

Is it safe to assume that

urlHelper.Action("Action", "Controller", routeValueDictionary);

is exactly equivalent to

urlHelper.RouteUrl("RouteName", routeValueDictionary);

Upvotes: 0

Views: 5356

Answers (2)

Nkosi
Nkosi

Reputation: 247423

Once there are no routes mapped above your displayed mapping that can match the route generated from

urlHelper.Action("Action", "Controller", routeValueDictionary);

then you would be safe in your assumption in using the route name.

if for example you have two routes defined like this...

routes.MapRoute(
    "AnotherRouteName",
    "{controller}/blah/{action}",
    new { controller = "Controller", action = "Action" }
);

routes.MapRoute(
    "RouteName",
    "Url",
    new { controller = "Controller", action = "Action" }
);

...then the first route would be matched by..

urlHelper.Action("Action", "Controller", routeValueDictionary);

UPDATE:

if you look at the source for UrlHelper

You will notice that internally they are calling the same overloads of the same methods with relevant arguments.

public virtual string Action(string actionName, string controllerName, object routeValues)
{
    return GenerateUrl(null /* routeName */, actionName, controllerName, TypeHelper.ObjectToDictionary(routeValues));
}

public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues)
{
    return GenerateUrl(null /* routeName */, actionName, controllerName, routeValues);
}

//...other code removed for brevity

public virtual string RouteUrl(string routeName, object routeValues, string protocol)
{
    return GenerateUrl(routeName, null /* actionName */, null /* controllerName */, protocol, null /* hostName */, null /* fragment */, TypeHelper.ObjectToDictionary(routeValues), RouteCollection, RequestContext, false /* includeImplicitMvcValues */);
}

Way too much code to post here. take a look at the class source to get a better understanding of what is happening under the hood.

Can't provide any more detail than that. I've gone all the way back to the source code.

Upvotes: 1

NightOwl888
NightOwl888

Reputation: 56889

No, not exactly.

urlHelper.RouteUrl only adds an additional filter to the route. You still must provide matching parameters (including controller and action) or it will return null instead of the URL you are expecting.

urlHelper.RouteUrl("RouteName", 
    new { controller = "Controller", action = "Action"[, other route values... ]);

The primary difference is that this filter will only make the routing framework check one route instead of all of the routes in order. This makes it impossible to match the wrong route when generating URLs, but it is still possible that incoming requests can match the wrong route by putting them in the route table in the wrong order - meaning you can potentially generate URLs from the route table that cannot actually be accessed in the application.

Unless you have thousands of routes in your route table, it is unlikely you will see any noticeable performance difference.

It is questionable whether there is any real benefit to this. In fact, both Action and RouteUrl end up calling the exact same method in the UrlHelper to generate the URL. Whether you use Action or RouteUrl to generate URLs, you should still make unit tests to ensure incoming routes match the route you intended and return the correct set of route values.

RouteUrl does have a benefit that Action doesn't have - you can pass null as the route name (or call an overload without route name), which allows you to pass it a ready-made set of route values without having to explicitly set separate parameters for controller and action. This makes RouteUrl act exactly like Action, but makes it more easy to integrate with code that manipulates the route values dynamically.

urlHelper.RouteUrl(routeValueDictionary);

Upvotes: 0

Related Questions