Razor actionlink autogenerating ?length=7 in URL? - asp.net-mvc

I have the link below on a razor page:
#Html.ActionLink("Create New Profile", "Create", "Profile", new { #class="toplink" })
It appears in thes source of view page as shown below:
Create New Profile
When I click on the link the URL is like this:
http://localhost:54876/admin/profile/create?length=7
I don't want ?length=7. Why is this auto generated?

The ActionLink override you are using matches to the (string linkText, string actionName, Object routeValues, Object htmlAttributes) override. So your "Profile" value is being passed to the routeValues parameter. The behavior of this function with respect to this parameter is to take all public properties on it and add it to the list of route values used to generate the link. Since a String only has one public property (Length) you end up with "length=7".
The correct overload you want to use is the (string linkText, string actionName, string controllerName, Object routeValues, Object htmlAttributes) and you call it loke so:
#Html.ActionLink("Create New Profile", "Create", "Profile", new {}, new { #class="toplink"})

I'm not sure the exact cause of this, but change it to:
#Html.ActionLink("Create New Profile", "Create", "Profile", new {}, new { #class="toplink" })
I don't know which overload MVC is picking when you leave off the last parameter (htmlattributes is the added one), but that will fix it. One of these days I'll investigate and figure out exactly what's going on.

Another thing to note, since you are defining the controller in the #ActionLink, which you may not need to do, for example, the view that your "Create New Profile" #ActionLink is expressed in might be "/admin/profile/index.cshtml", a view that lists existing profiles, in this case, you do not need to define the controller in the #ActionLink as the #ActionLink is already relative to the ProfileController, so your #ActionLink could be
#Html.ActionLink("Create New Profile", "Create", null, new { #class="toplink" })
I used null instead of new{} as the marked answer does, I think this is more appropriate myself. ActionLink overloads are not the most straightforward thing ever.

Related

Html Action link not taking me to the correct page

On my Home/index page which is returned by my home controller, I have added an HTML Action Link:
#Html.ActionLink("Create Ticket", "Create", "CustomerTicketInfo", new { #class = "btn btn-default" })
When clicked it should take me to a Create page. This Create page is returned by my CustomerTicketInfo controller which allows the user to create a ticket and then submit the ticket.
But when I click the action link, I get a server error/ resource not found. It's trying to go to: http://localhost:61517/Home/Create?Length=18, where a Create method does not exist. It exists in the CustomerTicketInfo Controller.
I'm not sure why this fails. I am stating the Action: Create. And the controller: CustomerTicketInfo in the Action link parameters. But yet it still wants to go to the Home Controller?
What am I doing wrong?
I could just you an tag, however, I want to do this the MVC way.
You are using an overload that is yielding undesirable results:
public static MvcHtmlString ActionLink
(this HtmlHelper htmlHelper,
string linkText,
string actionName,
object routeValues,
object htmlAttributes)
param 1: link text
param 2: action
param 3: not controller, but route data (note how the length of the string "CustomerTicketInfo" == 18)
param 4: HTML attributes
Instead, you probably want this:
#Html.ActionLink( "Create Ticket", "Create", "CustomerTicketInfo", null, new { #class = "btn btn-default" } )
Note the extra parameter, which causes the correct overload to be used.
Yes, Tim's solution would solve your problem. Since it's sometimes hard to remember the correct overloads I prefer constructing the #Html.ActionLink like below so I know what parameter I'm assigning value to.
#Html.ActionLink( linkText: "Create Ticket",
actionName: "Create",
controllerName: "CustomerTicketInfo",
routeValues: null,
htmlAttributes: new
{
#class = "btn btn-default"
})
In that way it's quite readable on what's what. If we need to pass in multiple values for the routeValues then it can be done like
routeValues: new
{
type = 'whatever type',
id = 'id value'
},

MVC: Html.ActionLink() Resolves to (Edit?Length=) instead of (Edit?Id=)

I have created an Admin area in my MVC 4 application. Under Views Folder called UserManage, I am using Grid.MVC to list out users (sets of 5) over several pages. In the Grid I am listing out the users details for viewing by Admin, and have added:
A column containing a checkbox [ ].
A column containing an EDIT link.
A CREATE button.
A DELETE button (to be used in conjunction with the checkbox for each row).
My User Details page is under my Admin Area in the following path: Project\Areas\Admin\Views\UserManage\Index.cshtml. On my EDIT liniks, I am attempting to pull up the view at Project\Areas\Admin\Views\UserManage\Edit.cshtml and pass the individual UserID to the View to pull up that users data.
In my current code below, my browser resolves to http://localhost:62517/Admin/UserManage/Edit?Length=4 with an IIS 8.0 404 Error (Controller cannot find UserID). However if I manually change the Length to Id as follows, everything works as intended and I end up on my Edit view: http://localhost:62517/Admin/UserManage/Edit?Id=4.
Here is my grid code for the Index.cshtml page. Does anyone know what I need to modify on my Html.ActionLink() so my route will resolved to ?Id= instead of ?Length=?:
<div class="overflowPrevention">
#Html.Grid(Model).Columns(columns =>
{
columns.Add().Encoded(false).Sanitized(false).SetWidth(30).RenderValueAs(o => #Html.CheckBox("checked", false));
columns.Add().Encoded(false).Sanitized(false).RenderValueAs(o => Html.ActionLink("Edit", "Edit", "Edit", new { id = "1" }));
}).AutoGenerateColumns()
</div>
You are using the wrong overload.
#Html.ActionLink(string linkText, string actionName, string controllerName, object htmlAttributes)
instead of
#Html.ActionLink(string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
You can just pass null for htmlAttributes if you don't need to use them:
Html.ActionLink("Edit", "Edit", "UserManage", new { id = "1" }, null)
I'm not sure why you are using Edit, Edit, Edit though. I think that was a typo so I have changed it to use UserManage as the controller name.

Link sends me to the wrong page

Hi I am trying to create a link to the Products controller but I seem to be doing something wrong.Here is my code:
#Html.ActionLink(subcategory, "Products")
When I click this link I want to be sent to something like this :
http://localhost:2100/Products
Instead I get sent to this page:
http://localhost:2100/Home/Products
If I open the Product page cotontroller and click the link I get sent herE:
http://localhost:2100/Products/Products
So how can I solve this problem cinsidering the fact that the link is in the _Layout.cshtml view?
Because you are setting the action part of route. Use this:
#Html.ActionLink(subcategory, "Index", "Products")
EDIT
See the method's signature that you are using:
Html.ActionLink(string linkText, string actionName, string controllerName)
The overload you are using is this one:
Html.ActionLink(string linkText, string actionName)
That means in this overload, you dont set the controller part of route. So, when we do not set a part of a route, it will be read automatically from current route that means: when we are in a route that it's controller is Home, your link's controller will be Home and you will get this route:
#Html.ActionLink(subcategory, "Products", "Home")
and when your are in a route with controller Products, you will get this route:
#Html.ActionLink(subcategory, "Products", "Products")
and so on.
Html.ActionLink has the following syntax :
public static MvcHtmlString ActionLink(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
string controllerName
)
As rightly answered by Javad_Amiry you can use the following code to create the link :
#Html.ActionLink(subcategory, "Index", "Products")
where,
subcategory : content from this will be used to create the linkText
"Index" : Is the action name.
"Products" : Is the controller name.
It would have been easier to help you out, had to posted the route config code too.

Edit and Create view using EditCreate.ascx partial in ASP.NET MVC

If you look at the NerdDinner example of creating and editing dinners then you see they use a partial (ViewUserControl or ASCX) DinnerForm to put the functionality of creating and editing dinners into one file because it is essential the same and they use it using RenderPartial("DinnerForm").
This approach seems fine for me but I've run into a problem where you have to add additonal route values or html properties to the Form tag.
This picks up the current action and controller automatically:
<% using (Html.BeginForm()) { %>
However, if I use another BeginForm() overload which allows to pass in enctype or any other attribute I have to do it like this:
<% using ("Create", "Section", new { modal = true }, FormMethod.Post, new { enctype = "multipart/form-data" }))
and as you can see we lose the ability to automatically detect in which View we are calling RenderPartial("OurCreateEditFormPartial"). We can't have hardcoded values in there because in Edit View this postback will fail or won't postback to the right controller action.
What should I do in this case?
What about adding the following HTML helpers:
public static MvcHtmlString CurrentAction(this HtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.RouteData.Values["action"];
}
public static MvcHtmlString CurrentController(this HtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.RouteData.Values["controller"];
}
Then you could go something like this:
<% using (Html.CurrentAction, Html.CurrentController, new { modal = true }, FormMethod.Post, new { enctype = "multipart/form-data" }))
Its not 100% perfect but you could also add an additional HTML helper which would streamline it a little more:
public static MvcForm BeginForm(this HtmlHelper htmlHelper, object routeValues, FormMethod method, object htmlAttributes)
{
return htmlHelper.BeginForm(Html.CurrentAction, Html.CurrentController, routeValues, method, htmlAttributes);
}
Let me know if this helps.
Cheers
I'm answering in an old thread because it came up number two on a Google search whilst I was looking for the same thing :) Found on this SO post:
Html.BeginForm and adding properties
With MVC3 (not sure about MVC2) you can pass null in for the action and controller and get the default routes that BeginForm() would use.
#Html.BeginForm(null, null, FormMethod.Post, new { enctype="multipart/form-data"})
Cheers!

asp.net mvc Html.ActionLink() keeping route value I don't want

I have the following ActionLink in my view
<%= Html.ActionLink("LinkText", "Action", "Controller"); %>
and it creates the following URL http://mywebsite.com/Controller/Action
Say I add an ID at the end like so: http://mywebsite.com/Controller/Action/53 and navigate to the page. On this page I have the markup I specified above. Now when I look at the URL it creates it looks like this:
http://mywebsite.com/Controller/Action/53 (notice the addition of the ID)
But I want it to remove the ID and look like it did originally, like this http://mywebsite.com/Controller/Action (notice no ID here)
Any ideas how I can fix this? I don't want to use hard coded URLs since my controller/actions may change.
The solution is to specify my own route values (the third parameter below)
<%= Html.ActionLink("LinkText", "Action", "Controller",
new { id=string.Empty }, null) %>
It sounds like you need to register a second "Action Only" route and use Html.RouteLink(). First register a route like this in you application start up:
routes.MapRoute("ActionOnly", "{controller}/{action}",
new { controller = "Home", action = "Index" } );
Then instead of ActionLink to create those links use:
Html.RouteLink("About","ActionOnly")
The problem is the built in methods take input from the URL you are currently on as well as what you supply. You could try this:
<%= Html.ActionLink("LinkText", "Action", "Controller", new { id = ""}) %>
That should manually wipe the id parameter.
Don't know why, but it didn't work for me (maybe because of Mvc2 RC). Created urlhelper method =>
public static string
WithoutRouteValues(this UrlHelper helper, ActionResult action,params string[] routeValues)
{
var rv = helper.RequestContext.RouteData.Values;
var ignoredValues = rv.Where(x=>routeValues.Any(z => z == x.Key)).ToList();
foreach (var ignoredValue in ignoredValues)
rv.Remove(ignoredValue.Key);
var res = helper.Action(action);
foreach (var ignoredValue in ignoredValues)
rv.Add(ignoredValue.Key, ignoredValue.Value);
return res;
}
If you either don't know what values need to be explicitly overridden or you just want to avoid the extra list of parameters you can use an extension method like the below.
View
The implementation details are in this blog post
I explicitly set the action name as "Action/". Seems a little like a hack but it's a quick fix.
#Html.ActionLink("Link Name", "Action/", "Controller")
Another way is to use ActionLink(HtmlHelper, String, String, RouteValueDictionary) overload, then there are no need to put null in the last parameter
<%= Html.ActionLink("Details", "Details", "Product", new RouteValueDictionary(new { id=item.ID })) %>
The overloads of Html.ActionLink are changed on the later versions of MVC. On MVC 5 and above. This is how to do this:
#Html.ActionLink("LinkText", "Action", "Controller", new { id = "" }, null)
Note I passed "" for id parameter and null for HTMLATTRIBUTES.
I needed my menu links to be dynamic. Rather than implement a lot of extra code and routing for every single page I simple dispensed with the HTML helper.
#item.MenuItemName

Resources