Как принять массив в качестве параметра действия контроллера 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-адресе.

Ответ 1

Связующее устройство по умолчанию ожидает этот 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)
{
    ...
}

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

Я скопировал/вставлял связующее устройство для модели Darin и украсил мое действие/параметр, но это не сработало. Я все еще получил 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.