HTML.ActionLink method
Asked Answered
P

10

264

Let's say I have a class

public class ItemController:Controller
{
    public ActionResult Login(int id)
    {
        return View("Hi", id);
    }
}

On a page that is not located at the Item folder, where ItemController resides, I want to create a link to the Login method. So which Html.ActionLink method I should use and what parameters should I pass?

Specifically, I am looking for the replacement of the method

Html.ActionLink(article.Title,
    new { controller = "Articles", action = "Details",
          id = article.ArticleID })

that has been retired in the recent ASP.NET MVC incarnation.

Politburo answered 14/10, 2008 at 9:16 Comment(2)
Documentation, for anyone looking for it: msdn.microsoft.com/en-us/library/…Interdisciplinary
@Danny Thanks, was looking for it on Google when I ended up here.Favianus
C
513

I think what you want is this:

ASP.NET MVC1

Html.ActionLink(article.Title, 
                "Login",  // <-- Controller Name.
                "Item",   // <-- ActionMethod
                new { id = article.ArticleID }, // <-- Route arguments.
                null  // <-- htmlArguments .. which are none. You need this value
                      //     otherwise you call the WRONG method ...
                      //     (refer to comments, below).
                )

This uses the following method ActionLink signature:

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

ASP.NET MVC2

two arguments have been switched around

Html.ActionLink(article.Title, 
                "Item",   // <-- ActionMethod
                "Login",  // <-- Controller Name.
                new { id = article.ArticleID }, // <-- Route arguments.
                null  // <-- htmlArguments .. which are none. You need this value
                      //     otherwise you call the WRONG method ...
                      //     (refer to comments, below).
                )

This uses the following method ActionLink signature:

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

ASP.NET MVC3+

arguments are in the same order as MVC2, however the id value is no longer required:

Html.ActionLink(article.Title, 
                "Item",   // <-- ActionMethod
                "Login",  // <-- Controller Name.
                new { article.ArticleID }, // <-- Route arguments.
                null  // <-- htmlArguments .. which are none. You need this value
                      //     otherwise you call the WRONG method ...
                      //     (refer to comments, below).
                )

This avoids hard-coding any routing logic into the link.

 <a href="/Item/Login/5">Title</a> 

This will give you the following html output, assuming:

  1. article.Title = "Title"
  2. article.ArticleID = 5
  3. you still have the following route defined

. .

routes.MapRoute(
    "Default",     // Route name
    "{controller}/{action}/{id}",                           // URL with parameters
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
);
Cloudy answered 14/10, 2008 at 14:19 Comment(13)
But, doesn't this give out a URL like /Item/Login?id=5 ?Elum
What's strange is if you miss out the last parameter, it appends for me ?Length=8 to the current actionHarrison
@Chris S - I know this is an old post, but the reason for the ?Length=8 is because you need to have a , null parameter AFTER your new { ... } ... because if you check the overloads of that method, it's thinking your paramters are htmlArguments ... not route arguments. To use the correct method, u need to use the method that has routeArguments, htmlArguments .. so just pass in null for that last htmlArgument. The first piece of code in this reply has it. I've updated this post so you can see that easily (ie. it doesn't scroll).Hyphen
Has anyone tried this with MVC 3? It seems that the ControllerName and ActionMethod lines in the sample above are flipped. Anyone else seen that?Lynnelle
@Steve Duitsman - confirmed. It has flipped indead. It happened with ASP.NET MVC 2 ...Hyphen
In MVC3 the id property is not found... the following should be used instead: @Html.ActionLink("Text","Action","Controller", new { item.ID }, null)Extrude
@JosephKingry I'm sorry, I know this post is old, but for this method, there are NO differences between MVC 1, 2, and 3. MVC 1 does NOT have the action and controller switched, and MVC 3 still requires correctly named Route arguments. If I am mistaken, please point me to some documentation.End
I've come back to this question and answer at least three times in my work. I wish I could upvote it more than once.Tampa
What's the difference between Html.Action and Html.ActionLink?Arguelles
Can someone tell me why the resulting HTML of this ActionLink is including the Index action in the link? How can I make this default? @Html.ActionLink(item.Name, "Index", "Forum", new { id = item.Name }, null) I want to do this with passing id as a string (which is working... just want to simplify /Forum/Index/StringId to /Forum/StringId. My routeConfig is set as it would be after File > New ProjectLoath
@Adhip This will give out as you stated.. To get it in the form Item/Login/5 you have to change the route arguments from "new { article.ArticleID }" to new {id = article.ArticleID }. Your action method parameter will also have to be named "id". If so the default route will pick it up.Setiform
I recommend using named parameters in this case, so everyone (the programmer and compiler) are clear on what is what: @Html.ActionLink(article.Title, actionName: "Item", controllerName: "Login", routeValues: new { article.ArticleID }, htmlAttributes: null)Trip
Html.ActionLink(article.Title, "Item", // <-- ActionMethod "Login", // <-- Controller Name. new { Id = article.ArticleID } )Extinguish
D
30

I wanted to add to Joseph Kingry's answer. He provided the solution but at first I couldn't get it to work either and got a result just like Adhip Gupta. And then I realized that the route has to exist in the first place and the parameters need to match the route exactly. So I had an id and then a text parameter for my route which also needed to be included too.

Html.ActionLink(article.Title, "Login", "Item", new { id = article.ArticleID, title = article.Title }, null)
Dunseath answered 9/3, 2009 at 11:57 Comment(3)
This is just what I needed - I had forgotten to add the final null argument. Thanks.Pint
Thanks for showing the mapping from route parameter name, too (e.g. new { id = ..., bar = ... }.Sacrosanct
Check this: codingfusion.com/Post/…Maybellemayberry
T
17

You might want to look at the RouteLink() method.That one lets you specify everything (except the link text and route name) via a dictionary.

Tithable answered 14/10, 2008 at 15:39 Comment(1)
Would be great to see an example of how that solves the issue; the MSDN page has lots of overloads and knowing what to look for could be confusingKilly
N
15

I think that Joseph flipped controller and action. First comes the action then the controller. This is somewhat strange, but the way the signature looks.

Just to clarify things, this is the version that works (adaption of Joseph's example):

Html.ActionLink(article.Title, 
    "Login",  // <-- ActionMethod
    "Item",   // <-- Controller Name
    new { id = article.ArticleID }, // <-- Route arguments.
    null  // <-- htmlArguments .. which are none
    )
Nuncupative answered 30/9, 2010 at 15:31 Comment(0)
A
12

what about this

<%=Html.ActionLink("Get Involved", 
                   "Show", 
                   "Home", 
                   new 
                       { 
                           id = "GetInvolved" 
                       }, 
                   new { 
                           @class = "menuitem", 
                           id = "menu_getinvolved" 
                       }
                   )%>
Aborning answered 9/10, 2010 at 7:37 Comment(0)
E
11
Html.ActionLink(article.Title, "Login/" + article.ArticleID, 'Item") 
Elum answered 14/10, 2008 at 13:47 Comment(1)
This really should have been marked as the answer since it does exactly what the person asking the question was looking for...however I will note that the marked answer did go into a great detail for the user in correctly setting up routes in various versions of MVC.Vertu
T
10

Use named parameters for readability and to avoid confusions.

@Html.ActionLink(
            linkText: "Click Here",
            actionName: "Action",
            controllerName: "Home",
            routeValues: new { Identity = 2577 },
            htmlAttributes: null)
Theriault answered 14/9, 2015 at 11:56 Comment(0)
Q
9

If you want to go all fancy-pants, here's how you can extend it to be able to do this:

@(Html.ActionLink<ArticlesController>(x => x.Details(), article.Title, new { id = article.ArticleID }))

You will need to put this in the System.Web.Mvc namespace:

public static class MyProjectExtensions
{
    public static MvcHtmlString ActionLink<TController>(this HtmlHelper htmlHelper, Expression<Action<TController>> expression, string linkText)
    {
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection);

        var link = new TagBuilder("a");

        string actionName = ExpressionHelper.GetExpressionText(expression);
        string controllerName = typeof(TController).Name.Replace("Controller", "");

        link.MergeAttribute("href", urlHelper.Action(actionName, controllerName));
        link.SetInnerText(linkText);

        return new MvcHtmlString(link.ToString());
    }

    public static MvcHtmlString ActionLink<TController, TAction>(this HtmlHelper htmlHelper, Expression<Action<TController, TAction>> expression, string linkText, object routeValues)
    {
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection);

        var link = new TagBuilder("a");

        string actionName = ExpressionHelper.GetExpressionText(expression);
        string controllerName = typeof(TController).Name.Replace("Controller", "");

        link.MergeAttribute("href", urlHelper.Action(actionName, controllerName, routeValues));
        link.SetInnerText(linkText);

        return new MvcHtmlString(link.ToString());
    }

    public static MvcHtmlString ActionLink<TController>(this HtmlHelper htmlHelper, Expression<Action<TController>> expression, string linkText, object routeValues, object htmlAttributes) where TController : Controller
    {
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection);

        var attributes = AnonymousObjectToKeyValue(htmlAttributes);

        var link = new TagBuilder("a");

        string actionName = ExpressionHelper.GetExpressionText(expression);
        string controllerName = typeof(TController).Name.Replace("Controller", "");

        link.MergeAttribute("href", urlHelper.Action(actionName, controllerName, routeValues));
        link.MergeAttributes(attributes, true);
        link.SetInnerText(linkText);

        return new MvcHtmlString(link.ToString());
    }

    private static Dictionary<string, object> AnonymousObjectToKeyValue(object anonymousObject)
    {
        var dictionary = new Dictionary<string, object>();

        if (anonymousObject == null) return dictionary;

        foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(anonymousObject))
        {
            dictionary.Add(propertyDescriptor.Name, propertyDescriptor.GetValue(anonymousObject));
        }

        return dictionary;
    }
}

This includes two overrides for Route Values and HTML Attributes, also, all of your views would need to add: @using YourProject.Controllers or you can add it to your web.config <pages><namespaces>

Qualitative answered 26/12, 2013 at 21:23 Comment(5)
I'm surprised more don't use this approach. It seems really dangerous to use string literals all over in your views to represent a controller/action.Anemography
Been looking for this all my lifeViolate
Tried this, didn't work. Gave me a blank string in the end - I assume because I have parameters in my functions.Violate
Can you post a github or other place with this code so I can take a look and see why it's not working for you?Qualitative
Nice use of the word fancypants. We don't see that enough.Neurotomy
O
1

With MVC5 i have done it like this and it is 100% working code....

@Html.ActionLink(department.Name, "Index", "Employee", new { 
                            departmentId = department.DepartmentID }, null)

You guys can get an idea from this...

Oxidize answered 25/8, 2015 at 13:14 Comment(0)
K
0

This type use:

@Html.ActionLink("MainPage","Index","Home")

MainPage : Name of the text Index : Action View Home : HomeController

Base Use ActionLink

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>_Layout</title>
    <link href="@Url.Content("~/Content/bootsrap.min.css")" rel="stylesheet" type="text/css" />
</head>
<body>
    <div class="container">
        <div class="col-md-12">
            <button class="btn btn-default" type="submit">@Html.ActionLink("AnaSayfa","Index","Home")</button>
            <button class="btn btn-default" type="submit">@Html.ActionLink("Hakkımızda", "Hakkimizda", "Home")</button>
            <button class="btn btn-default" type="submit">@Html.ActionLink("Iletişim", "Iletisim", "Home")</button>
        </div> 
        @RenderBody()
        <div class="col-md-12" style="height:200px;background-image:url(/img/footer.jpg)">

        </div>
    </div>
</body>
</html>
Kroll answered 17/5, 2017 at 20:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.