Extending the ActionLink Helper in MVC

Posted on January 1, 2012

The ActionLink Helper is used to generate anchor links in your views in MVC. The problem I’ve been having is that if the action on a controller gets renamed, or a controller gets moved to a new Area, its really hard to find all of the action links that reference the action or controller and update them.

With that in mind, I created a small helper object and added an extension overload to the ActionLink method to solve this problem.

To start off, here is my ActionLink overload

public static HtmlString ActionLink(this HtmlHelper helper, LinkData data)
        {
            return System.Web.Mvc.Html.LinkExtensions.ActionLink(helper, data.LinkText, data.Action, data.Controller, data.routeValues, data.htmlAttributes);
        }

As you can see this takes in a LinkData object which looks like this

public class LinkData
    {
        public String Controller { get; set; }
        public String Action { get; set; }
        public RouteValueDictionary routeValues { get; set; }
        public Dictionary<string,object> htmlAttributes { get; set; }
        public String LinkText { get; set; }

        public LinkData()
        {
            this.routeValues = new RouteValueDictionary();
            this.htmlAttributes = new  Dictionary<string,object>();
        }

        public LinkData(String key,Object data) : this()
        {
            AddRouteData(key, data);
        }

        public LinkData(String areaName)
            : this("area", areaName)
        {

        }

        public void AddRouteData(String key, object data)
        {
            routeValues.Add(key, data);
        }

        public void AddHtmlAttribute(String key, object data)
        {
            htmlAttributes.Add(key, data);
        }

        //over ride equals method for testing
        public override bool Equals(object obj)
        {
            if (obj is LinkData)
            {
                return this.Equals((LinkData)obj);
            }

            return false;
        }

        public bool Equals(LinkData obj)
        {
            if (obj.Action != this.Action)
            {
                return false;
            }

            if (obj.Controller != this.Controller)
            {
                return false;
            }

            return true;
        }
    }

This LinkData object represents the information you need to generate an action link. Its got a controller name, an action name, the display text for the actual anchor. You can add html attributes to it, and its even got a route dictionary in case you need to pass things like area name etc in it.

Now I simply generate a helper class to generate return me an instance of LinkData. In here I put the string values for the controllername, the area name, the action name etc. This is the only place this information is entered so if it ever changes I only update it here.

public static partial class LinkDataHelper
    {

        public static LinkData PageInArea()
        {
            //return a link to an action in an area
            return linkDataLink("some linkText", "ActionName", "ControllerName", "AreaName");
        }

        public static LinkData HomePage()
        {
            //return a link with no area
            return linkDataLink("Home", "Index", "Home");
        }

        private static LinkData linkDataLink(String linkText, String action, String controller)
        {
            return new LinkData() { LinkText = linkText, Action = action, Controller = controller };
        }

        private static LinkData linkDataLink(String linkText, String action, String controller, String area)
        {
          return new LinkData(area) { LinkText= linkText, Action = action, Controller = controller};
        }
    }

Finally on a view, to create a link to the home page I simply type

@Html.ActionLink(LinkDataHelper.HomePage())

and the link to the page in the area looks like so

@Html.ActionLink(LinkDataHelper.PageInArea())

I have also added some overloads to the link helper allowing me to send in the link text I want to display, and for edit links I send in a value that gets added to the routedictionary with the appropriate key. This small amount of effort has paid off wholesale when it comes to moving controllers, renaming actions, stopping typo’s etc.

 

If you have any comments of suggestions feel free to contact me or leave your thoughts below.

Categories: Asp.net MVC


Leave a Reply