ASP.Net MVC RouteData e matrizes

Se eu tiver uma ação como esta:

public ActionResult DoStuff(List stuff) { ... ViewData["stuff"] = stuff; ... return View(); } 

Eu posso atingi-lo com o seguinte URL:

 http://mymvcapp.com/controller/DoStuff?stuff=hello&stuff=world&stuff=foo&stuff=bar 

Mas no meu ViewPage, eu tenho esse código:

  

Infelizmente, o MVC não é inteligente o suficiente para reconhecer que a ação toma uma matriz e desenrola a lista para formar a rota de url apropriada. em vez disso, apenas faz um .ToString () no object que apenas lista o tipo de dados no caso de uma List.

Existe uma maneira de obter o Html.ActionLink para gerar uma URL apropriada quando um dos parâmetros da Ação de destino é uma matriz ou lista?

– editar –

Como Josh apontou abaixo, ViewData [“stuff”] é apenas um object. Eu tentei simplificar o problema, mas ao invés disso, causei um erro não relacionado! Eu estou realmente usando um ViewPage dedicado, então eu tenho um modelo ciente de tipo fortemente acoplado. O ActionLink realmente se parece com:

  

Onde ViewData.Model.Stuff é typescript como uma lista

Eu estou pensando que um HtmlHelper personalizado estaria em ordem.

  public static string ActionLinkWithList( this HtmlHelper helper, string text, string action, string controller, object routeData, object htmlAttributes ) { var urlHelper = new UrlHelper( helper.ViewContext.RequestContext ); string href = urlHelper.Action( action, controller ); if (routeData != null) { RouteValueDictionary rv = new RouteValueDictionary( routeData ); List urlParameters = new List(); foreach (var key in rv.Keys) { object value = rv[key]; if (value is IEnumerable && !(value is string)) { int i = 0; foreach (object val in (IEnumerable)value) { urlParameters.Add( string.Format( "{0}[{2}]={1}", key, val, i )); ++i; } } else if (value != null) { urlParameters.Add( string.Format( "{0}={1}", key, value ) ); } } string paramString = string.Join( "&", urlParameters.ToArray() ); // ToArray not needed in 4.0 if (!string.IsNullOrEmpty( paramString )) { href += "?" + paramString; } } TagBuilder builder = new TagBuilder( "a" ); builder.Attributes.Add("href",href); builder.MergeAttributes( new RouteValueDictionary( htmlAttributes ) ); builder.SetInnerText( text ); return builder.ToString( TagRenderMode.Normal ); } 

você pode routevalues seus valores de routevalues com um índice de matriz como:

 RouteValueDictionary rv = new RouteValueDictionary(); rv.Add("test[0]", val1); rv.Add("test[1]", val2); 

isso resultará na querystring contendo test=val1&test=val2

isso pode ajudar?

Combinando os dois methods funciona bem.

 public static RouteValueDictionary FixListRouteDataValues(RouteValueDictionary routes) { var newRv = new RouteValueDictionary(); foreach (var key in routes.Keys) { object value = routes[key]; if (value is IEnumerable && !(value is string)) { int index = 0; foreach (string val in (IEnumerable)value) { newRv.Add(string.Format("{0}[{1}]", key, index), val); index++; } } else { newRv.Add(key, value); } } return newRv; } 

Em seguida, use esse método em qualquer método de extensão que exija routeValues ​​com IEnumerable (s) nele.

Infelizmente, essa solução alternativa também é necessária no MVC3.

Existe uma biblioteca chamada Unbinder , que você pode usar para inserir objects complexos em rotas / urls.

Funciona assim:

 using Unbound; Unbinder u = new Unbinder(); string url = Url.RouteUrl("routeName", new RouteValueDictionary(u.Unbind(YourComplexObject))); 

Isso só funcionará como uma extensão para o UrlHelper e apenas fornecerá uma boa URL pronta para colocar em qualquer lugar em vez de uma tag inteira, e também preservará a maioria dos outros valores de rota para qualquer outra URL específica em uso … o URL específico mais amigável que você tem (menos os valores IEnumerable) e, em seguida, basta acrescentar os valores da string de consulta no final.

 public static string ActionWithList(this UrlHelper helper, string action, object routeData) { RouteValueDictionary rv = new RouteValueDictionary(routeData); var newRv = new RouteValueDictionary(); var arrayRv = new RouteValueDictionary(); foreach (var kvp in rv) { var nrv = newRv; var val = kvp.Value; if (val is IEnumerable && !(val is string)) { nrv = arrayRv; } nrv.Add(kvp.Key, val); } string href = helper.Action(action, newRv); foreach (var kvp in arrayRv) { IEnumerable lst = kvp.Value as IEnumerable; var key = kvp.Key; foreach (var val in lst) { href = href.AddQueryString(key, val); } } return href; } public static string AddQueryString(this string url, string name, object value) { url = url ?? ""; char join = '?'; if (url.Contains('?')) join = '&'; return string.Concat(url, join, name, "=", HttpUtility.UrlEncode(value.ToString())); } 

Eu não estou na minha estação de trabalho, mas que tal algo como:

 <%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = (List)ViewData["stuff"] }, null) %> 

ou o typescript:

 <%= Html.ActionLink("click here", "DoMoreStuff", "MoreStuffController", new { stuff = (List)ViewData.Model.Stuff }, null) %>