Sergio
Sergio

Reputation: 6948

Ajax.ActionLink and "action" parameter - weird behavior

I've got couple Ajax calls in a project using Ajax.ActionLink helper, looking like:

@Ajax.ActionLink("Edit", "MyEditAction", "MyController", new {id = item.Id, action = item.Action}, new AjaxOptions {HttpMethod = "POST"})

What's weird here = is that action parameter gets filtered out of URL parameters, even if i rewrite it to @action = item.Action. But renaming this parameter e.g. to act fixes problem.

Anybody know why it's happening?

Upvotes: 0

Views: 523

Answers (2)

Sergio
Sergio

Reputation: 6948

The problem lays deep in .NET framework. There's a class RouteValuesHelpers in System.Web.Mvc assembly, that has following method

public static RouteValueDictionary MergeRouteValues(string actionName, string controllerName, RouteValueDictionary implicitRouteValues, RouteValueDictionary routeValues, bool includeImplicitMvcValues)
{
    // Create a new dictionary containing implicit and auto-generated values
    RouteValueDictionary mergedRouteValues = new RouteValueDictionary();

    if (includeImplicitMvcValues)
    {
        // We only include MVC-specific values like 'controller' and 'action' if we are generating an action link.
        // If we are generating a route link [as to MapRoute("Foo", "any/url", new { controller = ... })], including
        // the current controller name will cause the route match to fail if the current controller is not the same
        // as the destination controller.

        object implicitValue;
        if (implicitRouteValues != null && implicitRouteValues.TryGetValue("action", out implicitValue))
        {
            mergedRouteValues["action"] = implicitValue;
        }

        if (implicitRouteValues != null && implicitRouteValues.TryGetValue("controller", out implicitValue))
        {
            mergedRouteValues["controller"] = implicitValue;
        }
    }

    // Merge values from the user's dictionary/object
    if (routeValues != null)
    {
        foreach (KeyValuePair<string, object> routeElement in GetRouteValues(routeValues))
        {
            mergedRouteValues[routeElement.Key] = routeElement.Value;
        }
    }

    // Merge explicit parameters when not null
    if (actionName != null)
    {
        mergedRouteValues["action"] = actionName;
    }

    if (controllerName != null)
    {
        mergedRouteValues["controller"] = controllerName;
    }

    return mergedRouteValues;
}

which is called by UrlHelper.GenerageUrl method.

So far we see that either implicit or explicit action/controller name would replace action or controller parameters in route values even if it's supposed to be query string or other url parameters.

Don't know why M$ did it that way, but i guess it's more a bug than feature

Upvotes: 1

faby
faby

Reputation: 7558

I've done some test and the action parameter is always overridden by Action parameter of the ActionLink. I think that there is something in the framework that overrides this parameter that make yours useless.

I have done the same test with controller parameter like this

 @Html.ActionLink("Register", "ActionName",routeValues: new {@action="fakeAction".ToString(CultureInfo.InvariantCulture), controller="fakeController".ToString(CultureInfo.InvariantCulture)})

these parameters overrides current controller and broke the actionLink link that search inside fakeAction controller

If I leave only action parameter in the controller

public ActionResult Register(string action)
{
      return View();
}

action parameter in input is always "Register" instead "fakeAction"

Upvotes: 1

Related Questions