Как передать несколько параметров в GET ASP.Net Web API?


136

Я использую .Net MVC4 Web API для (надеюсь) реализации API RESTful. Мне нужно передать несколько параметров в систему и заставить ее выполнить какое-то действие, а затем вернуть список объектов в качестве результатов. В частности, я передаю две даты и возвращаю записи, которые попадают между ними. Я также отслеживаю возвращенные записи, чтобы последующие вызовы не обрабатывались в системе повторно.

Я рассмотрел несколько подходов:

  1. Сериализация параметров в одну строку JSON и выделение их в API. http://forums.asp.net/t/1807316.aspx/1

  2. Передайте параметры в строке запроса.
    Каков наилучший способ передать несколько параметров запроса в успокоительный API?

  3. Определение параметров в маршруте: api / controller / date1 / date2

  4. Использование POST, которое по своей сути позволяет мне передавать объект с параметрами.

  5. Исследование ODATA, поскольку веб-API (в настоящее время) поддерживает его. Я еще ничего не сделал с этим, поэтому я не очень знаком с этим.

Кажется, что правильные методы REST указывают, когда данные извлекаются, вы должны использовать GET. Однако GET также должен быть нулевым (не вызывает побочных эффектов), и мне интересно, нарушает ли это моя конкретная реализация, поскольку я отмечаю записи в системе API, следовательно, я создаю побочные эффекты.

Это также привело меня к вопросу о поддержке переменных параметров. Если список входных параметров изменится, было бы утомительно пересматривать ваш маршрут для Варианта 3, если это часто случается. И что может произойти, если параметры определены во время выполнения ...

В любом случае, для моей конкретной реализации, какой выбор (если есть) кажется лучшим?

Ответы:


10

Что означает эта маркировка записи? Если это используется только для целей регистрации, я бы использовал GET и отключил бы все кэширование, так как вы хотите регистрировать каждый запрос для этих ресурсов. Если у маркировки записи есть другая цель, POST - путь. Пользователь должен знать, что его действия влияют на систему, а метод POST является предупреждением.


Под пометкой я имею в виду просто отслеживание того, какие записи обрабатываются и возвращаются, чтобы последующие вызовы не повторяли их. В моем случае я просто делаю вставку в другую таблицу, чтобы отслеживать, какие из них обрабатываются.
sig606

Прямо сейчас у меня это реализовано как ПОЧТА, в основном по той причине, которую вы сказали - действия происходят, и потребитель знает о них. Кроме того, это кажется простым и наиболее гибким в отношении передачи различных данных.
sig606

@ sig606: POST - это путь для меня, но ваш протокол не выглядит безопасным. Что если что-то случится и записи будут получены на стороне клиента, но не обработаны из-за ошибки? Вы больше не вернете их, и клиент останется с потерянными данными.
LukLed

Прямо сейчас мой API возвращает записи только после того, как они были обработаны. Таким образом, потребитель передает API две даты. Записи между этими двумя датами обрабатываются и помечаются. Затем данные возвращаются вызывающей стороне. Я полагаю, что если что-то случится во время обработки или после обработки до достижения клиента, у меня возникла проблема.
sig606

141

Я думаю, что самый простой способ - это просто использовать AttributeRouting.

В вашем контроллере очевидно, зачем вам это в вашем глобальном WebApiConfigфайле?

Пример:

    [Route("api/YOURCONTROLLER/{paramOne}/{paramTwo}")]
    public string Get(int paramOne, int paramTwo)
    {
        return "The [Route] with multiple params worked";
    }

В {}имена должны соответствовать вашим параметрам.

Просто, теперь у вас есть отдельное устройство, GETкоторое обрабатывает несколько параметров в этом случае.


12
Это круто. Большинство людей рекомендуют настроить маршрут в WebApiConfigфайле, но это действительно лучше.
Райк

4
Действительно, мы (большинство людей) рекомендуем иметь централизованную область управления для вашей конфигурации. В случае веб-API (Microsoft или иным способом) централизованные шаблоны для REST являются ключевыми. Маршрутизация атрибутов симпатична, но делает одноразовые исключения слишком заманчивыми.
Дэвид Бец

3
Согласен, мне нужно обновить свой ответ на самом деле. Есть намного лучший способ сделать несколько параметров с GET. Написал это, когда я был новичком в WebAPI, теперь я не использую AttributeRouting (если я просто не хочу создавать новый контроллер) и передаю все параметры в QueryString, они отображаются автоматически. Обновление, когда я получаю шанс, чтобы люди не использовали этот старый метод
Марк Писак - Trilon.io

Есть ли способ установить Routeдля именованных параметров (например, параметров запроса)?
Шимми Вайцхандлер

1
Если требуется имя метода действия, его можно изменить, чтобы приспособить его. [Route ("api / YOURCONTROLLER / Get / {paramOne} / {paramTwo}")] открытая строка Get (int paramOne, int paramTwo) {return "что-то"; }
Даш

49

Просто добавьте новый маршрут к WebApiConfigзаписям.

Например, позвонить:

public IEnumerable<SampleObject> Get(int pageNumber, int pageSize) { ..

Добавить:

config.Routes.MapHttpRoute(
    name: "GetPagedData",
    routeTemplate: "api/{controller}/{pageNumber}/{pageSize}"
);

Затем добавьте параметры в вызов HTTP:

GET //<service address>/Api/Data/2/10 

10
Это, кажется, единственный ответ, который перечисляет все части. Я хотел бы, чтобы кто-то лучше описал, как использовать api/controller?start=date1&end=date2стиль URI.
Hot Licks

@ Горячий ответ Эндрю Верига хорошо работает с аргументами строки запроса. По сути, вы связываете имена строк запроса со свойствами класса и передаете их в свой метод. Ваш метод будет принимать один аргумент класса, помеченный атрибутом [FromUri], и будет иметь аргументы строки запроса в качестве своих свойств.
Дэвид Петерсон

Отличный материал. Спасибо!
Уго Нава Копп

привет @ HotLicks и GrahamWright, как вы думаете, вы можете ответить на этот вопрос? Спасибо, stackoverflow.com/questions/57565318/...

45

Мне просто нужно было реализовать API RESTfull, где мне нужно передать параметры. Я сделал это, передав параметры в строке запроса в том же стиле, который описан в первом примере Марка «api / controller? Start = date1 & end = date2»

В контроллере я использовал подсказку от URL раскола в C #?

// uri: /api/courses
public IEnumerable<Course> Get()
{
    NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    var system = nvc["System"];
    // BL comes here
    return _courses;
}

В моем случае я звонил в WebApi через Ajax в виде:

$.ajax({
        url: '/api/DbMetaData',
        type: 'GET',
        data: { system : 'My System',
                searchString: '123' },
        dataType: 'json',
        success: function (data) {
                  $.each(data, function (index, v) {
                  alert(index + ': ' + v.name);
                  });
         },
         statusCode: {
                  404: function () {
                       alert('Failed');
                       }
        }
   });

Надеюсь, это поможет...


2
Я предполагаю, что вы не используете WebApi, потому что ParameterBinding автоматически сопоставит вашу строку запроса с параметрами вашего метода api ...
emp

1
Да, лучшим способом было бы использовать такие атрибуты, как [Route ("api / DbMetaData / {system} / {searchString}")], а затем добавить туда параметры в Get (строка system, string searchString) и затем вызвать с помощью " ... api / DbMetaData / mysystem / mysearchstring "
Найджел

Я использовал его пример в своем C # MVC WebApi, и он работал нормально. +1 например
Si8

38

Я нашел отличное решение на http://habrahabr.ru/post/164945/

public class ResourceQuery
{
   public string Param1 { get; set; }
   public int OptionalParam2 { get; set; }
}

public class SampleResourceController : ApiController
{
    public SampleResourceModel Get([FromUri] ResourceQuery query)
    {
        // action
    }
}

5
Подсказка здесь - [FromUri]
трансопортер

2
Хотя статья на русском языке, @tranceporter прав. «FromUri» выглядит как отличный способ получить параметры из URL. Еще одна статья, которая может оказаться полезной: asp.net/web-api/overview/formats-and-model-binding/…
Грег

Это то, чем я занимаюсь уже довольно давно, и это отлично работает! Я также рекомендовал бы это решение.
Дэвид Петерсон

Если вы вызываете другой вспомогательный метод (не тот Get), вы все еще можете его использовать [FromUri]? Я не могу заставить это работать.
Jocull

8

Использование GET или POST четко объясняется @LukLed . Что касается способов передачи параметров, я бы предложил использовать второй подход (я тоже не очень разбираюсь в ODATA ).

1. Сериализация параметров в одну строку JSON и выделение их в API. http://forums.asp.net/t/1807316.aspx/1

Это не удобно для пользователя и SEO

2. Передать параметры в строке запроса. Каков наилучший способ передать несколько параметров запроса в успокоительный API?

Это обычный предпочтительный подход.

3. Определение параметров в маршруте: api / controller / date1 / date2

Это определенно не очень хороший подход. Это заставляет чувствовать, что кто-то date2является субресурсом, date1а это не так. Оба параметра являются параметрами запроса date1и date2находятся на одном уровне.

В простом случае я хотел бы предложить такой URI,

api/controller?start=date1&end=date2

Но мне лично нравится приведенный ниже шаблон URI, но в этом случае мы должны написать собственный код для сопоставления параметров.

api/controller/date1,date2

На самом деле, это были мои объяснения. Я думаю, что LukLed осветил мои теги и ссылку URL.
sig606

Что касается SEO, в этом случае это не будет применяться. Этот код будет «сервер-сервер», поэтому мне было бы все равно, обнаружит ли его когда-либо внешний мир. На самом деле, я должен убедиться, что предприняты надлежащие меры безопасности, чтобы избежать произвольного доступа. Мне пришлось выполнить сериализацию JSON для другой части системы (похоже, это ошибка при попытке выложить большие списки объектов obj, поэтому мне пришлось сериализовать в строку), так что в этом случае это не будет большой проблемой. ,
sig606

1
Я надеюсь, что у вас уже есть ответы, почему вы задаете вопрос?
VJAI

2
Извините за этот поздний ответ, Марк. Я попробовал несколько решений, но не был уверен, какое из них лучше, и пытался придерживаться стандартных отраслевых подходов, поэтому я разместил здесь сообщение на SO.
sig606

1
@Mark Что-то похожее на следующее: stackoverflow.com/questions/9681658/… ?
RredCat


3
 [Route("api/controller/{one}/{two}")]
    public string Get(int One, int Two)
    {
        return "both params of the root link({one},{two}) and Get function parameters (one, two)  should be same ";
    }

Оба параметра корневой ссылки ({one}, {two}) и параметров функции Get (один, два) должны быть одинаковыми


2

Я знаю, что это действительно старый, но я недавно хотел то же самое, и вот что я нашел ...

    public HttpResponseMessage Get([FromUri] string var, [FromUri] string test) {
        var retStr = new HttpResponseMessage(HttpStatusCode.OK);
        if (var.ToLower() == "getnew" && test.ToLower() == "test") {
            retStr.Content = new StringContent("Found Test", System.Text.Encoding.UTF8, "text/plain");
        } else {
            retStr.Content = new StringContent("Couldn't Find that test", System.Text.Encoding.UTF8, "text/plain");
        }

        return retStr;
    }

Так что теперь в ваш адрес / URI / ...

HTTP (s): // myURL / API / myController / вар = getnew & тест = тест

Результат: «Найден тест»


HTTP (s): // myURL / API / myController / вар = getnew & тест = ничего

Результат: «Не удалось найти этот тест»


Мне лично нравится этот стиль в C #, потому что я могу изменить сигнатуру оригинального метода и перегрузить именно то, что я пытаюсь выполнить, не изменяя настройки маршрутизации. Надеюсь, что это поможет другим, кто привык к этому (возможно, устаревшему) подходу делать запрос GET.
Рик Риггс

1
Мне пришлось создать API событий, который используется сторонним приложением календаря, использующим этот подход. Я рад, что нашел этот ответ!
clayRay


0
    public HttpResponseMessage Get(int id,string numb)
    {
        //this will differ according to your entity name
        using (MarketEntities entities = new MarketEntities())
        {
          var ent=  entities.Api_For_Test.FirstOrDefault(e => e.ID == id && e.IDNO.ToString()== numb);
            if (ent != null)
            {
                return Request.CreateResponse(HttpStatusCode.OK, ent);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Applicant with ID " + id.ToString() + " not found in the system");
            }
        }
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.