Передать переменное число параметров строки запроса в одно действие контроллера

Я создаю API, который имеет контроллер с одним действием GET:

[Route("api/xxxxx/{param1:int}/{param1:int}")]
public IHttpActionResult Get(int param1, int param2) {
    // method body...
}

URL-адреса будут иметь следующий формат:

/api/xxxxx/1/1?p1=5&p2=hello&p3=20161108
/api/xxxxx/1/1?p1=active

Количество и имена параметров строки запроса будут отличаться.

Я хочу передать параметры строки запроса в метод controller, но я не могу жестко закодировать их в сигнатуру метода из-за различных имен и номеров. Есть ли способ сделать это? Я пытался вызватьvar qsParams = ControllerContext.Request.GetQueryNameValuePairs();, но я получаю ресурс не найден ошибка при попытке запросить любой URL со строкой запроса, учитывая Routeатрибут, показанный выше.

Я придумал одну альтернативу: использовать значения маршрута вместо параметров строки запроса, затем использовать catch-all {*tags}и передать его в качестве параметра метода:

[Route("api/xxxxx/{param1:int}/{param1:int}/{*tags}")]
public IHttpActionResult Get(int param1, int param2, string tags) {
    // method body...
}

С URL в формате

/api/xxxxx/1/1/5/john/20161108
/api/xxxxx/1/1/active

Это работает, но я бы предпочел использовать строку запроса, чтобы иметь возможность использовать именованные ключи вместо того, чтобы полагаться на порядок параметров (кроме того, использование строки запроса кажется лучшим концептуальным соответствием тому, что я делаю).

Итак, как я могу передать переменные параметры строки запроса в действие контроллера? Я говорю «передать» параметры, но они не обязательно должны быть переданы в качестве параметров метода, пока я могу получить доступ к параметрам строки запроса из тела метода, получая URL-адрес со строкой запроса, чтобы разрешить к рассматриваемому действию.

РЕДАКТИРОВАТЬ:

Стоит отметить, что создание нескольких методов действий для каждого возможного набора параметров не является опцией.

EDIT 2:

Я вижу два прямых решения, если они возможны:

  1. Передайте всю строку запроса методу action в виде одной строки
    параметр. Затем я мог бы вручную проанализировать строку запроса.
  2. Уметь использовать ControllerContext.Request.GetQueryNameValuePairs()
    внутри тела метода, не добавляя соответствующие параметры к
    подпись метода.

Тем не менее, я не выяснил, возможны ли эти две вещи, хотя кажется вероятным, что одна или обе будут.

2 ответа

  1. Если вы хотите отправить объект на контроллер, вы можете получить его с помощью [FromBody]
    Думайте, что сущность-это самый простой способ передать ее.

    F. e.

    [HttpPost]
    [Route("api/xxxxx/send")]
    public void SendReuqest([FromBody] Entity name)
    

    надеюсь понять вашу проблему правильно.

  2. Я публикую ответ на альтернативы документа, которые я придумал. Я знаю некоторые (все?) из них будут hacky. Однако…

    Ответ
    Используйте метод GetQueryNameValuePairs. Это первое, что я попытался сделать, но у меня, должно быть, было что-то другое в атрибуте маршрута или сигнатуре метода, потому что я получал ошибку «не найден» раньше. Теперь, однако, это работает отлично. Это делает весь этот вопрос и ответ в основном спорным для меня.

    Пример URL:

    /api/xxxxx/1/1?p1=5&p2=john&p3=20161108
    

    Экшен:

    [Route("api/xxxxx/{param1:int}/{param1:int}")]
    public IHttpActionResult Get(int param1, int param2) {
        var qsParams = ControllerContext.Request.GetQueryNameValuePairs();
        // rest of method body...
    }
    

    Вариант 1
    Используйте параметр строки одиночного запроса с пользовательским форматом, который контроллер понимает и может анализировать.

    Пример URL:

    /api/xxxxx/1/1?qs=p1~5|p2~john|p3~20161108
    

    Экшен:

    [Route("api/xxxxx/{param1:int}/{param1:int}")]
    public IHttpActionResult Get(int param1, int param2, string qs) {
        string[] qsParamsArray = qs.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
        IDictionary<string, string> qsParams = new Dictionary<string, string>();
        foreach (string p in qsParamsArray) {
            string[] kv = p.Split(new string[] { "~" }, StringSplitOptions.None);
            if (String.IsNullOrWhiteSpace(kv[0])) {
                return NotFound();
            }
            qsParams.Add(kv[0], kv[1]);
        }
        // Use qsParams as desired...
    }
    

    Вариант 2
    Поместите параметры строки запроса в маршрут вместо строки запроса. Необходимо полагаться на упорядочение параметров.

    Пример URL:

    /api/xxxxx/1/1/5/john/20161108
    

    Экшен:

    [Route("api/xxxxx/{param1:int}/{param1:int}/{*tags}")]
    public IHttpActionResult Get(int param1, int param2, string tags) {
        // parse the "tags" parameter here...
        // rest of method body...
    }
    

    Вариант 3
    Жесткий код максимальное количество необязательных параметров с общими именами и конкретными параметрами строки запроса для имен и значений параметров.

    Пример URL:

    /api/xxxxx/1/1?name1=p1&value1=5&name2=p2&value2=john&name3=p3&value3=20161108
    

    Экшен:

    [Route("api/xxxxx/{param1:int}/{param1:int}")]
    public IHttpActionResult Get(
        int param1, 
        int param2, 
        string name1 = null, 
        string value1 = null, 
        string name2 = null, 
        string value2 = null, 
        string name3 = null, 
        string value3 = null, 
        string name4 = null, 
        string value4 = null, 
        ..., 
        string nameNMAX = null, 
        string valueNMAX = null
    ) {
        // method body...
    }