Как принять массив в качестве параметра действия контроллера ASP.NET MVC?

У меня ASP.net MVC контроллер называется Designs у которого есть действие со следующей подписью:

public ActionResult Multiple(int[] ids)

Однако, когда я пытаюсь перейти к этому действию, используя URL:

http://localhost:54119/Designs/Multiple?ids=24041,24117

ids Параметр всегда нулевой. Есть ли способ заставить MVC конвертировать ?ids= Параметр запроса URL в массив для действия? Я видел разговоры об использовании фильтра действий, но насколько я могу судить, он будет работать только для тех POST, где массив передается в данных запроса, а не в самом URL.

4 ответа

Решение

Связыватель модели по умолчанию ожидает этот URL:

http://localhost:54119/Designs/Multiple?ids=24041&ids=24117

для того, чтобы успешно связать с:

public ActionResult Multiple(int[] ids)
{
    ...
}

И если вы хотите, чтобы это работало со значениями, разделенными запятыми, вы можете написать пользовательский механизм связывания модели:

public class IntArrayModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (value == null || string.IsNullOrEmpty(value.AttemptedValue))
        {
            return null;
        }

        return value
            .AttemptedValue
            .Split(',')
            .Select(int.Parse)
            .ToArray();
    }
}

и тогда вы могли бы применить эту модель связывания к конкретному аргументу действия:

public ActionResult Multiple([ModelBinder(typeof(IntArrayModelBinder))] int[] ids)
{
    ...
}

или применить его глобально ко всем параметрам целочисленного массива в вашем Application_Start в Global.asax:

ModelBinders.Binders.Add(typeof(int[]), new IntArrayModelBinder());

и теперь действие вашего контроллера может выглядеть так:

public ActionResult Multiple(int[] ids)
{
    ...
}

Если продолжить ответ Дарина Димитрова, то, что вы можете сойти с рук, это принять простое string в параметре URL и преобразовав его в массив самостоятельно:

public ActionResult Multiple(string ids){
  int[] idsArray = ids.Split(',').Select(int.Parse).ToArray();
  /* ...process results... */
}

Если во время этого вы получите ошибку разбора (потому что кто-то передал вам некорректный массив), вы можете заставить свой обработчик исключений вернуть 400 Bad Request ошибка вместо значения по умолчанию, более недружественный 404 Not Found ошибка, которую MVC возвращает, когда конечная точка не найдена.

Вы также можете использовать этот формат URL, и ASP.NET MVC сделает все за вас. Но не забудьте применить кодировку URL.

?param1[0]=3344&param1[1]=2222

.Net Core Ответ

Для тех, кто приезжает сюда в последнее время, вы можете сделать это в.Net Core с помощью:

http://localhost:54119/Designs/Multiple?ids=24041&ids=24117

и:

public ActionResult Multiple([FromQuery] int[] ids)
{
    ...
}

Я не знаю, откуда взялась строка URL Groky, но у меня была та же проблема с некоторым javascript, вызывающим мой контроллер / действие. Было бы создать URL-адрес null, 1 или много "идентификаторов" из списка с множественным выбором (что уникально для решения, которым я собираюсь поделиться).

Я скопировал / вставил пользовательскую подшивку модели Дарина и украсил свое действие / параметр, но это не сработало. Я все еще получил null ценный int[] ids, Даже в "безопасном" случае, когда у меня действительно было много удостоверений личности.

Я закончил тем, что изменил javascript для создания массива параметров ASP.NET MVC вроде

?ids=1&ids=2

Я должен был сделать некоторые глупости, хотя

ids || []                 #=> if null, get an empty array
[ids || []]               #=> if a single item, wrap it in an array
[].concat.apply([], ...)  #=> in case I wrapped an array, flatten it

Итак, полный блок был

ids = [].concat.apply([], [ids || []])
id_parameter = 'ids=' + ids.join('&ids=')

Это грязно, но это первый раз, когда мне приходилось так взламывать в javascript.

Другие вопросы по тегам