【问题标题】:Passing IEnumerable property in RouteValues of ActionLink在 ActionLink 的 RouteValues 中传递 IEnumerable 属性
【发布时间】:2018-02-28 11:54:27
【问题描述】:

想象一个对象定义如下:

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

在我看来,我有这个动作链接:

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

ActionLink 的 html 结果将是:

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

我的问题是,如何得到这个结果:

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

【问题讨论】:

    标签: c# razor asp.net-mvc-5 html-helper


    【解决方案1】:

    你可以试试string.Join。像这样的

    @Ajax.ActionLink(
                "Your text", -- <
                "ActionName", -- Index
                new
                {
                   MyList =string.Join(",", new List<string>() {"foo", "bar"}),
                  otherPropertiesIfyouwant = YourValue
                }, -- rounteValues
                new AjaxOptions { UpdateTargetId = "..." }, -- Your Ajax option --optional
                new { @id = "back" } -- Your html attribute - optional
                )   
    

    【讨论】:

      【解决方案2】:

      您不能使用@Html.ActionLink() 为集合生成路由值。在内部,该方法(以及所有生成 url 的 MVC 方法)使用属性的 .ToString() 方法来生成路由/查询字符串值(因此您的 MyList=System.Collections.Generic.List%601%5BSystem.String%5D" 结果)。

      该方法没有对复杂属性或集合执行递归是有充分理由的 - 除了丑陋的查询字符串之外,您可能很容易超出查询字符串限制并引发异常。

      不清楚为什么要这样做(通常的方法是传递对象的 ID,然后根据 ID 在 GET 方法中再次获取数据),但是您可以通过创建一个RouteValueDictionary 带有索引属性名称,并在您的@Ajax.ActionLink() 方法中使用它。

      在视图中

      @{
          var rvd = new RouteValueDictionary();
          rvd.Add("MyList[0]", "foo");
          rvd.Add("MyList[1]", "bar");
      }
      @Ajax.ActionLink("<", "Index", rvd, new AjaxOptions())
      

      这将使 GET 到

      public ActionResult Index(MyViewModel model)
      

      但是,您还必须将 MyList 设为属性(DefaultModelBinder 不绑定字段)

      public class MyViewModel{
          public List<string> MyList { get; set; } // add getter/setter
      }
      

      那么 POST 方法中model.MyList 的值将是["foo", "bar"]

      【讨论】:

      • 谢谢斯蒂芬,它是用于在 MyList 集合中没有很多项目的表单过滤器,但我保留您对查询字符串限制的警告!我们有没有办法自动进行 RouteValueDictionary 转换?我将尝试使用反射从您的示例中开发一个
      • 你可以编写自己的扩展方法来完成它。但是你的问题只显示了 2 个硬编码值,所以现在还不清楚你真正想要什么
      【解决方案3】:

      使用 Stephen 的 anwser,我开发了一个辅助扩展方法来执行此操作。

      注意 URL 查询字符串限制:如果集合的值过多,则 URL 可能大于 255 个字符并引发异常。

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

      【讨论】:

      • 你不能只使用带有方法 GET 和隐藏值的表单吗?这似乎比你的扩展简单得多
      • 是的,我可以,但我有 4 个链接/视图。使用 helper 更“漂亮”
      猜你喜欢
      • 1970-01-01
      • 2015-02-16
      • 2011-05-05
      • 1970-01-01
      • 2016-01-17
      • 1970-01-01
      • 2013-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多