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.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
Graviton
  • 81,782
  • 146
  • 424
  • 602

10 Answers10

512

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
);
Graviton
  • 81,782
  • 146
  • 424
  • 602
Joseph Kingry
  • 8,188
  • 4
  • 36
  • 52
  • 8
    But, doesn't this give out a URL like /Item/Login?id=5 ? – Adhip Gupta Oct 14 '08 at 14:28
  • 22
    What's strange is if you miss out the last parameter, it appends for me ?Length=8 to the current action – Chris S Aug 19 '09 at 10:22
  • 34
    @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). – Pure.Krome Aug 06 '10 at 04:35
  • 7
    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? – Steve Duitsman Sep 09 '10 at 20:50
  • @Steve Duitsman - confirmed. It has flipped indead. It happened with ASP.NET MVC _2_ ... – Pure.Krome Oct 21 '10 at 05:03
  • 10
    In MVC3 the id property is not found... the following should be used instead: `@Html.ActionLink("Text","Action","Controller", new { item.ID }, null)` – Gavin Coates May 16 '11 at 20:07
  • 2
    @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](http://msdn.microsoft.com/en-us/library/dd504972%28v=VS.90%29.aspx), and [MVC 3 still requires correctly named Route arguments](http://msdn.microsoft.com/en-us/library/dd504972%28v=VS.98%29.aspx). If I am mistaken, please point me to some documentation. – Scott Rippey Nov 08 '11 at 01:53
  • 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. – Yes - that Jake. Jul 09 '12 at 17:02
  • What's the difference between `Html.Action` and `Html.ActionLink`? – Shimmy Weitzhandler Dec 20 '12 at 04:17
  • 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 Project – Tom Mar 24 '13 at 20:23
  • @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. – John Jun 28 '13 at 09:17
  • 2
    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)` – ThisGuy Dec 14 '14 at 23:33
  • Html.ActionLink(article.Title, "Item", // <-- ActionMethod "Login", // <-- Controller Name. new { Id = article.ArticleID } ) – Atif Mar 08 '21 at 10:10
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)
Community
  • 1
  • 1
Jeff Widmer
  • 4,746
  • 6
  • 37
  • 51
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.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Haacked
  • 58,045
  • 14
  • 90
  • 114
  • 4
    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 confusing – Simon Martin Mar 15 '13 at 10:07
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
    )
abatishchev
  • 98,240
  • 88
  • 296
  • 433
agez
  • 624
  • 1
  • 7
  • 17
12

what about this

<%=Html.ActionLink("Get Involved", 
                   "Show", 
                   "Home", 
                   new 
                       { 
                           id = "GetInvolved" 
                       }, 
                   new { 
                           @class = "menuitem", 
                           id = "menu_getinvolved" 
                       }
                   )%>
George Stocker
  • 57,289
  • 29
  • 176
  • 237
Hasan
  • 121
  • 1
  • 2
11
Html.ActionLink(article.Title, "Login/" + article.ArticleID, 'Item") 
Adhip Gupta
  • 7,063
  • 7
  • 34
  • 46
  • 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. – Indy-Jones Aug 19 '14 at 17:04
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)
guneysus
  • 6,203
  • 2
  • 45
  • 47
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>

Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
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...

Aleksandr M
  • 24,264
  • 12
  • 69
  • 143
Sohail Malik
  • 305
  • 1
  • 2
  • 12
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>
Serdin Çelik
  • 165
  • 1
  • 4