Why does Html.ActionLink render "?Length=4" - asp.net-mvc

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?

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" })

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" })

You forgot to add the HTMLAttributes parm.
This will work without any changes:
Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" },null)

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.

Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" }, new { })
This will take the overload:
string linkText, string actionName, string controllerName, Object routeValues, Object htmlAttributes

Just remove "Home" (name of the controller) so that the code would be:
Html.ActionLink("About", "About", new { hidefocus = "hidefocus" })

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" }))

This worked fine
#Html.ActionLink("Informationen", "About", "Home", new { area = "" }, new { #class = "nav-link" })
added new { area = "" }.

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()
...
}

With attribute names:
#Html.ActionLink(linkText: "SomeText", actionName: "SomeAction", controllerName: "SomeControllerName", routeValues: new { parameterName = parameterValue}, htmlAttributes: null)

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" })

Search for an answer to my question landed me here, basically it's the selection of correct overload of #Html.ActionLink
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

Related

Convert ActionLink to T4MVC ActionLink

Probably it should be very easy but I am not sure that I did it correctly, so I want to ask you how to convert the code below to T4MVC syntax:
#Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new {id = "loginLink"})
I tried to do this code and it works fine but I am not sure I did it 100% correct.
#Html.ActionLink("Log in", MVC.Account.Login(null, null), htmlAttributes: new { id = "loginLink" })
The Login method signature is:
public virtual async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
Thanks in advance.
Based on this example:
#Html.ActionLink("Delete Dinner", "Delete", "Dinners", new { id = Model.DinnerID }, null)
being transformed into this:
#Html.ActionLink("Delete Dinner", MVC.Dinners.Delete(Model.DinnerID))
Your implementation of ActionLink using T4MVC seems correct.
You include your link text - Log in
You include your Controller - Account
You include your Action Name/Method with parameters - Login(null, null)
The only thing that I can't find is the correct way to implement htmlAttributes but I was able to find this example. You might not even need to put htmlAttributes: new { id = "loginLink" }.. instead just try new { id = "loginLink" } and take out the htmlAttributes.
I hope this helps!

Wrong parameter in Query ActionLink MVC [duplicate]

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?
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" })
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" })
You forgot to add the HTMLAttributes parm.
This will work without any changes:
Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" },null)
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.
Html.ActionLink("About", "About", "Home", new { hidefocus = "hidefocus" }, new { })
This will take the overload:
string linkText, string actionName, string controllerName, Object routeValues, Object htmlAttributes
Just remove "Home" (name of the controller) so that the code would be:
Html.ActionLink("About", "About", new { hidefocus = "hidefocus" })
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" }))
This worked fine
#Html.ActionLink("Informationen", "About", "Home", new { area = "" }, new { #class = "nav-link" })
added new { area = "" }.
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()
...
}
With attribute names:
#Html.ActionLink(linkText: "SomeText", actionName: "SomeAction", controllerName: "SomeControllerName", routeValues: new { parameterName = parameterValue}, htmlAttributes: null)
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" })
Search for an answer to my question landed me here, basically it's the selection of correct overload of #Html.ActionLink
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

MVC 4: Sending a ViewModel from a View to another View. Some properties are getting null

I have a simple view like this:
#using MyProject.WebClient.Models
#model LoginClienteModel
<h1>#ViewBag.Title</h1>
#{
<text>
<h2>
<span>Olá #Model.Login . </span>
</h2>
<h3>
<span>Info: (#Model.ProperyOne)</span>
</h3>
</text>
}
<br/>
#Html.ActionLink("Option 1", "OptOne", "Home", new {pdModel = new OptOneModel{Login = Model.Login,Data = DateTime.Now.Date}});
When this view is showed, all data from model is displayed correctly. You can see I've another ActionLink, pointing to action OptOne. That action requires a parameter pdModel of type OptOneModel. As you can see, I instantiate it using current model values.
But when my Action is executed, Login property is null, only Data is not null.
public ActionResult OptOne(OptOneModel pdModel)
{
return View(pdModel); // <-- Here only Data property is not null
}
I'm lost. I can't see what is wrong with that.
Unfortunately, you can't pass a complex type into a route value that way for an ActionLink. Manual invocation of an Action, I believe you can, but not for a link. So:
#Html.ActionLink("Option 1", "OptOne", "Home", new {pdModelId = Model.YourUniqueId, dateRendered = DateTime.Now.Date});
Meanwhile, server side:
public ActionResult OptOne(int pdModelId, DateTime dateRendered)
{
// retrieve model again based on your Id
return View(pdModel);
}
You cannot use hyperlink to pass Model. It only work with Post.
Instead, you can use routeValues to generate query string.
#Html.ActionLink("Option 1", "OptOne", "Home",
new { Model.Login, Data = DateTime.Now.Date }, null)
public ActionResult OptOne(string login, DateTime data)
{
// Do something with login and data.
return View();
}
Use either ActionLink overload variation,
ActionLink(string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
#Html.ActionLink("Option 1", "OptOne", "Home", new OptOneModel{ Login = Model.Login, Data = DateTime.Now.Date}, null);
OR
ActionLink(string linkText, string actionName, object routeValues)
#Html.ActionLink("Option 1", "OptOne", new OptOneModel{ Login = Model.Login, Data = DateTime.Now.Date});
hope this helps.

Passing parameter to controller action from a Html.ActionLink

Is there anything wrong with this html? I want to have a link in the masterpage to navigate to "CreateParts" view. I have action 'CreateParts' which have a parameter parentPartId in the controller 'PartList'.
<li id="taskAdminPartCreate" runat="server">
<%= Html.ActionLink("Create New Part", "CreateParts", "PartList", new { parentPartId = 0 })%></li>
My controller action is like
public ActionResult CreateParts(int parentPartId)
{
HSPartList objHSPart = new HSPartList();
objHSPart.Id = parentPartId;
return View(objHSPart);
}
When I click on 'Create New Part' in the menu in SiteMaster, I get exception. Please help me out of this.
You are using incorrect overload. You should use this overload
public static MvcHtmlString ActionLink(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
string controllerName,
Object routeValues,
Object htmlAttributes
)
And the correct code would be
<%= Html.ActionLink("Create New Part", "CreateParts", "PartList", new { parentPartId = 0 }, null)%>
Note that extra parameter at the end.
For the other overloads, visit LinkExtensions.ActionLink Method. As you can see there is no string, string, string, object overload that you are trying to use.
You are using the incorrect overload of ActionLink. Try this
<%= Html.ActionLink("Create New Part", "CreateParts", "PartList", new { parentPartId = 0 }, null)%>
Addition to the accepted answer:
if you are going to use
#Html.ActionLink("LinkName", "ActionName", "ControllerName", new { #id = idValue, #secondParam= = 2 },null)
this will create actionlink where you can't create new custom attribute or style for the link.
However, the 4th parameter in ActionLink extension will solve that problem. Use the 4th parameter for customization in your way.
#Html.ActionLink("LinkName", "ActionName", "ControllerName", new { #id = idValue, #secondParam= = 2 }, new { #class = "btn btn-info", #target = "_blank" })

URL parameters not appearing in ASP.MVC when using variant of Html.BeginForm

I've got a view that defines a form as
<% using (Html.BeginForm( "Update", "CcisCase", FormMethod.Post, new { id = "ccisEditForm" } ))
with a submit button:
In the RegisterRoutes method (in the HttpApplication-derived class in global.asax.cs), I've got:
routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" );
routes.MapRoute(
"CcisCase",
"CcisCase/{action}/{cmDatabaseId}/{caseId}",
new { Controller = "CcisCase", Action = "CcisCaseEdit", caseId = "" } );
The url generated by MVC ends with "/Update" but there are no parameters. What am I doing wrong?
Thanks,
Bob
What parameters are you expecting to see? A post does not append parameters to the querystring, a FormMethod.Get would. And, that overload with the id is the collection of HTML attributes to render for the tag (which I'm assuming you knew, but just in case).
HTH.
Your route contains a parameter {caseId} but your BeginForm only defines an id value.
new {id = "cssEditForm"}
You need something like this to include the caseId value
using (Html.BeginForm( "Update", "CcisCase", FormMethod.Post, new { caseId = 1, id = "ccisEditForm" }
If your action isn't using the id="ccisEditForm" value then you can remove that for less code clutter.
I figured out what my problem was. I had to pass the existing route data as follows:
using (Html.BeginForm( "Update", "CcisCase", ViewContext.RouteData.Values, FormMethod.Post, new Dictionary<string, object> { { "id", "ccisEditForm" } } ))

Resources