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.
Related
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.
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.
I decided primarily for SEO reasons to add the "rel" to my action link, but am not sure that the way I have gone about this is going to follow "best practices." I simply created a new Extension method as shown below.
Is this the best way to go about doing this? Are there things that should be modified in this approach?
VIEW
<%= Html.ActionLink("Home", "Index", "Home")
.AddRel("me")
.AddTitle("Russell Solberg")
%>
EXTENSION METHODS
public static string AddRel(this string link, string rel)
{
var tempLink = link.Insert(link.IndexOf(">"), String.Format(" rel='{0}'", rel));
return tempLink;
}
public static string AddTitle(this string link, string title)
{
var tempLink = link.Insert(link.IndexOf(">"), String.Format(" title='{0}'", title));
return tempLink;
}
You can add any extra html parameter very easily and don't need to write your own extension methods
<%= Html.ActionLink("Home", "Index", "Home", null,
new { title="Russell Solberg", rel="me"}) %>
You can add attributes to the action link with anonymous class passed as fourth parameter:
<%= Html.ActionLink("Home", "Index", null,new{ #title="Russell Solberg", #rel="me" }) %>
The # sign is used to allow you to specify attribute names that are c# reserved keywordk (like class).
I would probably not do it that way as that will make this possible for any string. You can already do this with the action link without creating your own extensions methods. Like this:
<%=Html.ActionLink("Home", "Index", "Home", null, new {title = "Russell Solberg", rel = "me"}) %>
Personally I prefer to use Url.Action() and write the <a /> tag myself as I think thats more readable.
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!
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