Як прийняти масив як параметр дії контролера ASP.NET MVC?


84

У мене називається контролер ASP.net MVC, Designsякий має дію з таким підписом:

public ActionResult Multiple(int[] ids)

Однак, коли я намагаюся перейти до цієї дії за допомогою url:

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

idsПараметр завжди нульовий. Чи є спосіб отримати MVC для перетворення ?ids=параметра запиту URL-адреси в масив для дії? Я бачив розмови про використання фільтру дій, але, наскільки я можу зрозуміти, це буде працювати лише для POST, де масив передається в даних запиту, а не в самій URL-адресі.

Відповіді:


150

За замовчуванням підшивка моделі очікує таку 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_Startin Global.asax:

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

і тепер ваша дія контролера може виглядати так:

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

2
Я пропав безвісти [FromUri]. public ActionResult Multiple([FromUri]int[] ids) {} (GET)
C0d1ngJammer

1
@Darin чи є спосіб застосувати спеціальне прив'язування глобально, але просто ігнорувати для конкретних дій? Я не міг знайти спосіб зробити це: stackoverflow.com/questions/45379040 / ...
ДАК

15

Щоб продовжити відповідь Даріна Димитрова , вам можна уникнути, прийнявши простий stringпараметр у своєму URL-адресі та перетворивши його в масив самостійно:

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

Якщо при цьому ви отримуєте помилку синтаксичного аналізу (оскільки хтось передав вам неправильно сформований масив), ви можете змусити обробник винятків повернути 400 Bad Requestпомилку замість типової, більш недружньої 404 Not Foundпомилки, яку MVC повертає, коли кінцеву точку не знайдено.


9

Ви також можете використовувати цей формат URL-адреси, і ASP.NET MVC зробить все за вас. Але не забудьте застосувати кодування URL.

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

6

Я не знаю, звідки походив рядок URL-адреси Грокі, але у мене була та сама проблема з деяким 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.


1
Просто цікаво, чи немає в цьому останньому реченні пропущеного "не" перед "перший раз". В іншому випадку вам пощастить!
DCShannon

1
@DCShannon: ха-ха, я бачу вашу думку! Але це було вперше. Я не впевнений, чи подібні речі є нормальними, чи я переборщую.
Ентоні Мастреан,

0

.Net Core Answer

Для тих, хто прийшов сюди нещодавно, ви можете зробити це в .Net Core за допомогою:

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

і:

public ActionResult Multiple([FromQuery] int[] ids)
{
    ...
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.