Bilal Fazlani
Bilal Fazlani

Reputation: 6977

MVC - Given a route name, can I get the default action name and controller name?

Given a route name, can I get the default action name and controller name?

routes.MapRoute(
      name: "MonthlyCalendar",
      url: "FMB/Calendar/{jamaatName}/{year}/{month}",
      defaults: new { controller = "FMB", action = "MonthlyCalendar", 
         jamaatName = UrlParameter.Optional,year = UrlParameter.Optional,
         month=UrlParameter.Optional}
);

Upvotes: 1

Views: 5620

Answers (4)

Darin Dimitrov
Darin Dimitrov

Reputation: 1039498

No, of course that you cannot get controller and action name from just a route name. A route mapping might look like this: {controller}/{action}/{id}. That's the only thing you could get if you only have a route name.

If on the other hand you have a full url such as http://example.com/Home/Index then this is an entirely different story. Now you can get the controller=Home and action=Index from the RouteData.


UPDATE:

It seems that you are attempting to extract the default values for the controller and action from your routing configuration given the route name. This can easily be done by storing the route name when registering it in the DataTokens property:

RouteTable.Routes.MapRoute(
    "foo",
    "{controller}/{action}", 
    new { controller = "Home", action = "Index" }
).DataTokens["__RouteName"] = "foo";

and then:

var route = RouteTable.Routes.OfType<Route>().FirstOrDefault(x => 
    x.DataTokens.ContainsKey("__RouteName") && 
    (string)x.DataTokens["__RouteName"] == "foo"
);
if (route != null)
{
    var defaultController = route.Defaults["controller"];
    var defaultAction = route.Defaults["action"];
}

The reason why you need to store the route name in the DataTokens is because this information is not available in the Route instance.


UPDATE:

At some point MS added an indexer to RouteCollection to lookup by name, so the above is no longer necessary:

 ((System.Web.Routing.Route)Url.RouteCollection["MyRouteName"]).Defaults

You should probably check first to make sure it exists to avoid null exception.

Upvotes: 5

Peter Pompeii
Peter Pompeii

Reputation: 1445

I've created this extension method that adds the "active" css class to a route link. This method gets the default action and controller from the route based on route name, if an action and controller is not provided in the RouteValueDictionary.

You can get the default action from the route in the RouteTable, however you need to cast the return value as Route instead of RouteBase.

Example:

var action = (RouteTable.Routes["Default"] as Route).Defaults["action"] as string;

Full Extension Method:

public static MvcHtmlString MenuRouteLink(this HtmlHelper htmlHelper, string linkText, string routeName, RouteValueDictionary routeValues,
    IDictionary<string, object> htmlAttributes)
{
    string currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
    string currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");

    var route = RouteTable.Routes[routeName] as Route;
    if (route != null)
    {
        routeValues = routeValues ?? new RouteValueDictionary();
        string routeAction = (routeValues["action"] as string ?? route.Defaults["action"] as string) ?? string.Empty;
        string routeController = (routeValues["controller"] as string ?? route.Defaults["controller"] as string) ?? string.Empty;

        if (routeAction.Equals(currentAction, StringComparison.OrdinalIgnoreCase) && routeController.Equals(currentController, StringComparison.OrdinalIgnoreCase))
        {
            htmlAttributes = htmlAttributes ?? new Dictionary<string, object>();
            var currentCssClass = htmlAttributes["class"] as string ?? string.Empty;
            htmlAttributes["class"] = string.Concat(currentCssClass, currentCssClass.Length > 0 ? " " : string.Empty, "active");
        }
    }

    return htmlHelper.RouteLink(linkText, routeName, routeValues, htmlAttributes);
}

Upvotes: 3

Huske
Huske

Reputation: 9296

You can get the RouteData that is supposed to serve your request by reading ControllerContext.RouteData. RouteData object has Values which in turn has Keys that you can examine and apply to Values to get all the fragments of the route.

Normally, you can loop through RouteCollection (this depends in which context you are located, eg. ViewContext, or using HtmlHelper object) and extract each item and cast it to Route object. After that call Route.GetRouteData(YourHttpContextBaseHere) which return RouteData or null. If it returns an object, that Route served your request and examine Defaults property.

For example, lets say you are building an HTML helper and you have access to HtmlHelper object. THe following code shows you what you could do:

var defaults = (RouteValueDictionary) null;
foreach (var routeBase in html.RouteCollection)
{
    var route = (Route) routeBase;
    var routeData = route.GetRouteData(html.ViewContext.HttpContext);

    if (routeData != null) 
    {
        defaults = route.Defaults;
        break;
    }
}

// Do something with defaults object

Upvotes: 1

Piotr Stapp
Piotr Stapp

Reputation: 19828

You could look into System.Web.Routing.RouteTable.Routes. It contains all routes in system. But you don't find default action and controller if they are not specified

Upvotes: 0

Related Questions