Search code examples
c#razorasp.net-mvc-5html-helper

Passing IEnumerable property in RouteValues of ActionLink


Imagine an object defined like :

public class MyViewModel{
    public List<string> MyList { get; set; }
}

In my view, i have this Action link :

@Ajax.ActionLink("<", "Index", new MyViewModel() { MyList = new List<string>() {"foo", "bar"}}, new AjaxOptions())

The html result of the ActionLink will be :

<a class="btn btn-default" data-ajax="true" href="/Index?MyList=System.Collections.Generic.List%601%5BSystem.String%5D">&lt;</a>

My question is, how get this result rather :

<a class="btn btn-default" data-ajax="true" href="/Index?MyList=foo&MyList=bar">&lt;</a>

Solution

  • With Stephen's anwser, i have develop a helper extension method to do this.

    Be careful of the URL query string limit : if the collection has too many values, the URL can be greater than 255 characters and throw an exception.

    public static class AjaxHelperExtensions
    {
        public static MvcHtmlString ActionLinkUsingCollection(this AjaxHelper ajaxHelper, string linkText, string actionName, object model, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
        {
            var rv = new RouteValueDictionary();
            foreach (var property in model.GetType().GetProperties())
            {
                if (typeof(ICollection).IsAssignableFrom(property.PropertyType))
                {
                    var s = ((IEnumerable<object>)property.GetValue(model));
                    if (s != null && s.Any())
                    {
                        var values = s.Select(p => p.ToString()).Where(p => !string.IsNullOrEmpty(p)).ToList();
                        for (var i = 0; i < values.Count(); i++)
                            rv.Add(string.Concat(property.Name, "[", i, "]"), values[i]);
                    }
                }
                else
                {
                    var value = property.GetGetMethod().Invoke(model, null) == null ? "" : property.GetGetMethod().Invoke(model, null).ToString();
                    if (!string.IsNullOrEmpty(value))
                        rv.Add(property.Name, value);
                }
            }
            return AjaxExtensions.ActionLink(ajaxHelper, linkText, actionName, rv, ajaxOptions, htmlAttributes);
        }
    }