Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with more than one value per key in ASP.NET MVC 3?

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?

like image 827
Bruno Machado - vargero Avatar asked May 18 '11 16:05

Bruno Machado - vargero


People also ask

Which function is used to handle multiple submit buttons?

You can very well use helpers such as TextBoxFor() and LabelFor() if you so wish. There are two submit buttons - one with name attribute set to save and the other with name of cancel.

Can one action method have multiple views?

Yes, it's possible. Just make sure your views have same view model. From a technical stand point, views don't have to have the same view model implemented within the same action. There's just as long as the controller passes in the expected type.


1 Answers

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>
    
like image 72
Darin Dimitrov Avatar answered Sep 23 '22 03:09

Darin Dimitrov