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

Posted

技术标签:

【中文标题】如何处理 ASP.NET MVC 3 中每个键的多个值?【英文标题】:How to deal with more than one value per key in ASP.NET MVC 3? 【发布时间】:2011-08-28 05:45:20 【问题描述】:

我有以下问题:我正在使用的系统中最重要的功能之一是搜索页面。在此页面中,我有一些选项,例如每页记录、开始日期、结束日期和有问题的选项:类型。一个人必须有可能选择一种以上的类型(大多数时候,它们都会被选中)。为了完成这项工作,我创建了以下内容:

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

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

/5?period=9&events=1&events=3&recordsPerPage=10

可以看到创建了两个事件(这是我之前所说的类型)。此页面的操作方法将List&lt;long&gt; 作为其参数之一,它表示两个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"] 设置值时会擦除以前的值。

你们知道如何使用它吗?

【问题讨论】:

【参考方案1】:

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

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

    手动生成这个锚点:

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

【讨论】:

这是一个很好的答案,我几乎认为它在第一次尝试时会起作用......但我们正在谈论编程,但它从来没有。我遇到的问题是生成的链接现在看起来像 /5?period=9&amp;amp;events=1&amp;amp;events=3&amp;amp;recordsPerPage=10&amp;amp;page=2 @Bruno,我可能会使用自定义模型绑定器。就我回答的第二部分而言,我已经通过删除 Html.AttributeEncode 调用来修复它,这在这种情况下是不必要的。【参考方案2】:

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

【讨论】:

【参考方案3】:

您应该编写针对 routeValue 集合的扩展方法或自定义模型绑定器,始终将您的 Event 参数转换为列表。如果您始终将 Event 视为一个列表,那么通常长度为 1 的列表将缓解您面临的大部分问题。

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

【讨论】:

以上是关于如何处理 ASP.NET MVC 3 中每个键的多个值?的主要内容,如果未能解决你的问题,请参考以下文章

我应该如何处理 Window Phone / WCF / ASP.NET MVC 应用程序的用户身份?

ASP.NET Core MVC 502 bad gateway 超时如何处理

用户控件和 asp.net mvc

如何处理 ASP.NET SqlDataSource 中的空 CONTAINS() 查询参数?

ASP.NET vNext 如何处理 config.json 中的缓存、压缩和 MimeMap?

ASP.NET MVC 处理错误