ASP.Net MVC RouteData和数组

如果我有这样的动作:

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

我可以使用以下url点击它:

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

但在我的ViewPage中,我有这个代码:

  

不幸的是,MVC不够聪明,无法识别该动作采用数组,并展开列表以形成正确的URL路由。 相反,它只是在对象上执行.ToString(),它只列出了List中的数据类型。

当其中一个目标Action的参数是数组或列表时,有没有办法让Html.ActionLink生成一个正确的URL?

– 编辑 –

正如Josh在下面指出的那样,ViewData [“stuff”]只是一个对象。 我试图简化问题,但引起了一个无关的错误! 我实际上使用的是专用的ViewPage ,因此我有一个紧密耦合的类型感知模型。 ActionLink实际上看起来像:

  

其中ViewData.Model.Stuff被键入为List

我认为自定义的HtmlHelper是有序的。

  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 ); } 

你可以使用数组索引为你的routevalues添加后缀,如下所示:

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

这将导致包含test=val1&test=val2的查询字符串

那可能有帮助吗?

结合这两种方法很有效。

 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; } 

然后在任何需要带有IEnumerable的routeValues的扩展方法中使用此方法。

遗憾的是,这种解决方法也需要在MVC3中使用。

有一个名为Unbinder的库 ,可用于将复杂对象插入到路径/ URL中。

它的工作原理如下:

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

这只是作为UrlHelper的扩展,只是提供一个很好的url,可以放在任何地方而不是整个标签,它也将保留大部分其他路由值,用于任何其他特定url…正在使用你拥有的最友好的特定url(减去IEnumerable值),然后在最后附加查询字符串值。

 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())); } 

我不在我的工作站,但是如下:

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

或打字:

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