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

发布于 2024-11-08 02:33:09 字数 1271 浏览 2 评论 0 原文

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

<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 作为其参数之一,它表示两个事件 值。当我想将其与 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"] 的值删除之前的值。

你们知道如何使用它吗?

I have the following problem: one of the system I'm working in most important features is a search page. In this page I have some options, like records per page, starting date, ending date, and the problematic one: type. One must have the possibility to choose more than one type (most of the time, all of them will be selected). To make that work, i created the following:

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

It creates a listbox where I can choose more than one option, and when the form is submited, my query string will look like this:

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

There it is possible to see that two events (which is the type I was talking before) are created. The action method to this page takes a List<long> as one of its arguments, which represents that two events values. The problem begins when I want to use that with MVC Contrib. Their pager works just fine, but as I was requested, I created another pager, which displays links to five pages after and before the one the user is at. To do this, in a part of my code I have to do the following (which is very similar to the MVC Contrib pager, that works):

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

And then:

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

The problem is that it is a Dictionary, which makes the second time I set the value for routeValues["events"] erase the previous.

Do you guys have any idea on how to work with it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一个人的旅程 2024-11-15 02:33:09

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

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

    公共类 CommaSeparatedLongArrayModelBinder : DefaultModelBinder
    {
        公共覆盖对象 BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var Values = BindingContext.ValueProvider.GetValue(BindingContext.ModelName);
            if (values != null && !string.IsNullOrEmpty(values.AttemptedValue))
            {
                // TODO:这里最少的错误处理会很好
                返回值.AttemptedValue.Split(',').Select(x => long.Parse(x)).ToArray();
            }
            返回 base.BindModel(controllerContext, BindingContext);
        }
    }
    

    您将在Application_Start中注册:

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

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

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

    abc
    

Very good question. Unfortunately it is not easy to generate an url which has multiple query string parameters with the same name using the Html.ActionLink helper. So I can see two possible solutions:

  1. Write a custom model binder for long[] that is capable of parsing a comma separated values. This way you can keep your GetRoute method which will generate the following url: 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);
        }
    }
    

    which you will register in Application_Start:

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

    and then the following controller action will be able to understand the previous URL:

    public ActionResult Foo(long[] events, int page, int period, int recordsPerPage)
    {
        ...
    }
    
  2. Manually generate this anchor:

    <a href="@string.Format("{0}?{1}&page=5", Url.Action("action", "controller"), Request.QueryString)">abc</a>
    
幼儿园老大 2024-11-15 02:33:09

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

Try looking at WinTellect's PowerCollections, allows you to create a MultiDictionary, still can't have duplicate keys, but you can have multiple values per key.

如此安好 2024-11-15 02:33:09

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

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

You should write either extension methods that target the routeValue collection or a custom model binder that transforms your Event parameter into a list always. If you view Event always being a list, just a commonly length 1 list will alleviate most of the problems you face.

At this point you will just interact with a list interface. You could then write a custom binder to allow you to directly place that into the route correctly or you could unpack the list back into the query string. There's a software project based on this called Unbinder for unpacking objects into property/value pairs that you can easily use in query strings or other purposes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文