321

I'm VERY confused as to why this code

Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" })

results in this link:

<a hidefocus="hidefocus" href="/Home/About?Length=4">About</a>

The hidefocus part is what I was aiming to achieve, but where does the ?Length=4 come from?

Irvin Dominin
  • 30,819
  • 9
  • 77
  • 111
My Alter Ego
  • 3,392
  • 3
  • 18
  • 9

12 Answers12

344

The Length=4 is coming from an attempt to serialize a string object. Your code is running this ActionLink method:

public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, object htmlAttributes)

This takes a string object "Home" for routeValues, which the MVC plumbing searches for public properties turning them into route values. In the case of a string object, the only public property is Length, and since there will be no routes defined with a Length parameter it appends the property name and value as a query string parameter. You'll probably find if you run this from a page not on HomeController it will throw an error about a missing About action method. Try using the following:

Html.ActionLink("About", "About", new { controller = "Home" }, new { hidefocus = "hidefocus" })
roryf
  • 29,592
  • 16
  • 81
  • 103
  • @Blah_Blah these days I don't use this at all, prefer writing my own tags and just using Url.Action("Action", "Controller") – roryf May 13 '13 at 14:42
  • @roryf no worries ... this was used in a code review as a best practices, they didn't check the date. There really should be a way to filter the stackoverflow by date ... – THBBFT May 13 '13 at 15:32
  • 1
    Great answer. Just to add this also happens on Html.BeginRouteForm for the same reason. Html.BeginRouteForm("Route", "Action", FormMethod.Post)) Should be Html.BeginRouteForm("Route", new{ action = "AgentSignUp"}, FormMethod.Post) that gets rid of the weird length thing – radm4 Dec 04 '13 at 15:58
  • 1
    Also happens with `Url.Action()`. Changing from `Url.Action("Action", "Controller", new { area = "" })` to `Url.Action("Action", new { controller = "Controller", area = "" })` keeps the Length property from showing up. – John Washam Sep 05 '14 at 18:42
  • 2
    To avoid those kinds of situation, you can always specify what parameters you are passing, like: `Html.ActionLink("About", "About", "Home", routeValues: null, htmlAttributes: new { hidefocus = "hidefocus" })` –  Mar 13 '15 at 16:52
  • Thanks! :) That was a gotcha, it was looking for routevalues. – André Snede Jan 16 '16 at 01:50
200

The way I solved this is was adding a null to the fourth parameter before the anonymous declaration (new {}) so that it uses the following method overload: (linkText, actionName, controllerName, routeValues, htmlAttributes):

Html.ActionLink("About", "About", "Home", null, new { hidefocus = "hidefocus" })
Window
  • 1,377
  • 2
  • 13
  • 23
Manuel Castro
  • 2,460
  • 1
  • 19
  • 14
  • This is the best answer if you're not linking between Areas. If you need to specify the area for the link, you would need to specify the routeValues with the `controller` and the `area` to keep the Length property from showing up in the URL. – John Washam Sep 05 '14 at 18:43
  • @JohnWasham Actually, you don't need to specify the controller in the `routeValues` but only the area. For example: `Html.ActionLink("About", "About", "Home", new {@area = "Admin"}, new { hidefocus = "hidefocus" })` –  Mar 13 '15 at 16:55
  • 1
    @epiplon, the reason I specify the controller like that is because if you ever don't include htmlAttributes as the last argument of `ActionLink`, MVC will include a weird `Length=x` parameter at the end of the URL. For instance, put this on a page, then view the source of your page, and you'll see what I mean: `@Html.ActionLink("About", "About", "Home", new { area = "Admin" }, new { hidefocus = "hidefocus" })` `@Html.ActionLink("About", "About", "Home", new { area = "Admin" })` But if you put the `controller` entry in the `routeValues`, it will never put `Length=x` in the URL. – John Washam Mar 13 '15 at 19:18
  • @epiplon, you also don't need to use `@` in `@area = "Admin"`, just so you know. – John Washam Mar 13 '15 at 19:21
90

You forgot to add the HTMLAttributes parm.

This will work without any changes:

Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" },null)
Matt Hanson
  • 3,458
  • 7
  • 40
  • 61
Jesse Rose
  • 901
  • 6
  • 2
29

The parameters to ActionLink are not correct, it's attempting to use the "Home" value as a route value, instead of the anonymous type.

I believe you just need to add new { } or null as the last parameter.

EDIT: Just re-read the post and realized you'll likely want to specify null as the second last parameter, not the last.

5
Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" }, new { })

This will take the overload: string linkText, string actionName, string controllerName, Object routeValues, Object htmlAttributes

user2254436
  • 491
  • 3
  • 10
  • 24
3

Just remove "Home" (name of the controller) so that the code would be:

Html.ActionLink("About", "About", new { hidefocus = "hidefocus" })
Fil
  • 39
  • 2
3

Kindly use right overloaded method with five (5) parameters. Example:

@using (@Ajax.BeginForm("Register", "Account", null,
    new AjaxOptions
    {
        HttpMethod = "POST",
        OnSuccess = "OnSuccess",
        OnFailure = "OnFailure",
        OnBegin = "OnBegin",
        OnComplete = "OnComplete"
    }, new { @class = "form-login" }))
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • adding **null** after controller name was helpful in my case. – Munam Yousuf Dec 27 '16 at 07:46
  • This is effectively the same answer as @Jesse's answer with the added bonus that it covers the Ajax version, which is not what the OP asked for, but it is related to the same issue. – gcoulby Aug 27 '17 at 13:28
2

This worked fine

@Html.ActionLink("Informationen", "About", "Home", new { area = "" }, new { @class = "nav-link" })

added new { area = "" }.

M-Chen-3
  • 2,036
  • 5
  • 13
  • 34
elSchick
  • 21
  • 1
1

As Jonathon Watney pointed out in a comment, this also goes for

Html.BeginForm()

methods. In my case, I was in a Create.cshtml targeting the post request of the corresponding controller + Create action and had

using (Html.BeginForm("Create")) {
  @Html.AntiForgeryToken()
  ...
}

which was adding the querystring "?Length=6" to the form action when rendered. Hinted by roryf's approved answer and realizing the string length of "Create" is 6, I finally solved this by removing the explicit action specification:

using (Html.BeginForm()) {
      @Html.AntiForgeryToken()
      ...
    }
Frederik Struck-Schøning
  • 12,981
  • 8
  • 59
  • 68
1

With attribute names:

 @Html.ActionLink(linkText: "SomeText", actionName: "SomeAction", controllerName: "SomeControllerName", routeValues: new { parameterName = parameterValue}, htmlAttributes: null)
usefulBee
  • 9,250
  • 10
  • 51
  • 89
0

Perhaps others had the same issue and need to supply a class value via HTMLAttributes parm. Here's my solution:

@Html.ActionLink("About", "About", new { controller = "Home", area = "" }, new { hidefocus = "hidefocus", @class = "nav-item nav-link" })
Taersious
  • 751
  • 9
  • 20
0

Search for an answer to my question landed me here, basically it's the selection of correct overload of @Html.ActionLink enter image description here which matters.
I was selecting an overload which didn't exist, (without the last null), and MVC had no such overload, resulting in a false URL something like the OP mentioned.

A personal note: you can use anonymous types doesn't mean you can use any of the overloads- which do not exist? - make certain: it has to be defined!
- Came here in times of MVC 5.2

Irf
  • 4,285
  • 3
  • 36
  • 49