如何在ASP.NET MVC 3中处理每个键的多个值?

时间:2011-05-18 16:50:30

标签: c# asp.net-mvc-3 dictionary mvccontrib

我有以下问题:我在最重要的功能中使用的系统之一是搜索页面。在这个页面中,我有一些选项,如每页记录,开始日期,结束日期和有问题的一个:类型。必须有可能选择多种类型(大多数时候,所有这些都将被选中)。为了做到这一点,我创建了以下内容:

<div>
    <label>Eventos:</label>
    <div>
        @Html.ListBox("events", Model.Events, new { style = "width: 100%" })
    </div>
</div>

它创建了一个列表框,我可以在其中选择多个选项,当表单被提交时,我的查询字符串将如下所示:

  ?

/ 5周期= 9与活动= 1与活动= 3及recordsPerPage = 10

在那里可以看到创建了两个事件(我以前说过的类型)。此页面的操作方法将List<long>作为其参数之一,表示两个events值。当我想在MVC Contrib中使用它时,问题就开始了。他们的寻呼机工作得很好,但正如我的要求,我创建了另一个寻呼机,它显示了用户所在之前和之前的五个页面的链接。为此,在我的代码的一部分中,我必须执行以下操作(这与MVC Contrib寻呼机非常相似,有效):

public RouteValueDictionary GetRoute(int page)
{
    var routeValues = new RouteValueDictionary();
    foreach (var key in Context.Request.QueryString.AllKeys.Where(key => key != null))
    {
        routeValues[key] = Context.Request.QueryString[key];
    }

    routeValues["page"] = page;
    return routeValues;
}   

然后:

@Html.ActionLink(page.ToString(), action, controller, GetRoute(page), null)

问题是它是一个词典,它第二次设置routeValues["events"]的值擦除前一个。

你们对如何使用它有什么想法吗?

3 个答案:

答案 0 :(得分:4)

非常好的问题。不幸的是,使用Html.ActionLink帮助器生成具有多个具有相同名称的查询字符串参数的URL并不容易。所以我可以看到两种可能的解决方案:

  1. long[]编写一个能够解析逗号分隔值的自定义模型绑定器。这样您就可以保留GetRoute方法,该方法将生成以下网址:period=9&events=1%2C3&recordsPerPage=10&page=5

    public class CommaSeparatedLongArrayModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var values = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (values != null && !string.IsNullOrEmpty(values.AttemptedValue))
            {
                // TODO: A minimum of error handling would be nice here
                return values.AttemptedValue.Split(',').Select(x => long.Parse(x)).ToArray();
            }
            return base.BindModel(controllerContext, bindingContext);
        }
    }
    

    您将在Application_Start注册:

    ModelBinders.Binders.Add(typeof(long[]), new CommaSeparatedLongArrayModelBinder());
    

    然后以下控制器操作将能够理解以前的URL:

    public ActionResult Foo(long[] events, int page, int period, int recordsPerPage)
    {
        ...
    }
    
  2. 手动生成此锚:

    <a href="@string.Format("{0}?{1}&page=5", Url.Action("action", "controller"), Request.QueryString)">abc</a>
    

答案 1 :(得分:0)

尝试查看WinTellect的PowerCollections,允许您创建一个MultiDictionary,但仍然没有重复的键,但每个键可以有多个值。

答案 2 :(得分:0)

您应该编写以routeValue集合为目标的扩展方法,或者始终编写将Event参数转换为列表的自定义模型绑定器。如果您将“事件”视为一个列表,则只需一个通常长度为1的列表即可缓解您遇到的大多数问题。

此时您将只与列表界面进行交互。然后,您可以编写自定义绑定器以允许您直接将其放入路径中,或者您可以将列表解压缩回查询字符串。有一个基于这个名为Unbinder的软件项目,用于将对象解包为属性/值对,您可以在查询字符串或其他目的中轻松使用它们。