Як слід передавати кілька параметрів веб-API GET ASP.Net?


136

Я використовую .Net MVC4 Web API, щоб (сподіваюся) реалізувати RESTful api. Мені потрібно передати декілька параметрів до системи та дозволити їй виконати певну дію, а потім повернути список об’єктів як результати. Конкретно я проходжу в дві дати та повертаю записи, які потрапляють між ними. Я також стежу за поверненими записами, щоб наступні дзвінки не перероблялися в системі.

Я розглянув кілька підходів:

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

  2. Передайте парами у рядок запиту.
    Який найкращий спосіб передати кілька параметрів запиту спокійному api?

  3. Визначення парам в маршруті: api / controller / date1 / date2

  4. Використання POST, яке по суті дозволяє мені передавати об'єкт парамами.

  5. Дослідження ODATA, оскільки Web API (на даний момент) його підтримує. Я ще багато не робив з цим, тому не дуже знайомий з цим.

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

Це також привело мене до питання підтримки змінних параметрів. Якщо список вхідних параметрів змінюється, було б нудно переосмислити свій маршрут для вибору 3, якщо це трапляється багато. І що може статися, якщо параметри визначені під час виконання ...

У будь-якому випадку, для моєї конкретної реалізації, який вибір (якщо такий є) здається найкращим?

Відповіді:


10

Що означає це маркування записів? Якщо це використовується лише для цілей реєстрації, я б використовував GET і вимикав усі кешування, оскільки ви хочете реєструвати кожен запит для цих ресурсів. Якщо маркування записів має інше призначення, POST - це шлях. Користувач повинен знати, що його дії впливають на систему та метод POST - це попередження.


Під маркуванням я маю на увазі просто відстежувати, які записи обробляються та повертаються, щоб наступні дзвінки не повторювали їх. У моєму випадку я просто вкладаю в іншу таблицю, щоб відстежувати, які обробляються.
sig606

Зараз у мене це реалізується як POST переважно з тієї причини, яку ви сказали - дії трапляються, і споживач усвідомлює їх. Крім того, це здається простим і найскладнішим у відповідності з передачею різних даних.
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) {повернути "щось"; }
тире

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=date2URI стилю.
Гарячі лизання

@Hot Licks Відповідь Андрія Вериги добре працює з аргументами рядка запиту. По суті, ви прив'язуєте назви рядків запиту до властивостей класу та передаєте їх у свій метод. Ваш метод візьме аргумент одного класу, позначений атрибутом [FromUri], і буде мати свої аргументи рядка запиту як його властивості.
Девід Петерсон

Чудові речі. Дякую!
Х'юго Нава Копп

привіт @HotLicks та GrahamWright Ви думаєте, що можете відповісти на це питання? Спасибі, stackoverflow.com/questions/57565318 / ...

45

Мені просто довелося реалізувати RESTfull api, де мені потрібно передати параметри. Я зробив це, передавши параметри в рядку запиту в тому ж стилі, як описано в першому прикладі Марка "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 (строкова система, string searchString), а потім зателефонувати з " ... api / DbMetaData / mysystem / mysearchstring "
Nigel Findlater

Я використовував його приклад у своєму 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 / kontroler / 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 /? var = getnew & test = test

Результат: "Знайдений тест"


http (s): // myURL / api / myController /? var = getnew & test = що завгодно

Результат: "Не вдалося знайти цей тест"


Мені особисто подобається цей стиль в C #, тому що я можу змінити підпис оригінального методу і перевантажити саме те, що намагаюся виконати, не змінюючи налаштування маршрутизації. Сподіваюсь, це допомагає іншим, хто звик до цього (можливо, старовинного) підходу зробити запит GET.
Rick Riggs

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.