Добавление нескольких пользовательских вызовов «get» в Restful API - PullRequest
1 голос
/ 29 января 2020

Я работал только с несколькими Restful API и мне нужно было его создать. В конечном итоге мне нужен API, и я надеялся на аспект Restful, но эта часть не является основной целью.

Я создал прототип, и все вызовы basi c html работали нормально. Затем я хотел перейти на другие типы звонков. Я просмотрел много статей и фрагментов, но ни одна из них, похоже, не отвечает на этот вопрос. Я использую Почтальон для тестирования. Прямо сейчас у меня есть два базовых c вызова «Get», оба с тремя строковыми параметрами, понимающими, что они имеют одинаковую подпись, но разные имена. Я получаю ошибку, связанную с неоднозначностью. Любая помощь приветствуется

В моей настройке указано следующее:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var config = new HttpConfiguration();

        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "ApiByName",
            routeTemplate: "api/{controller}/{name}",
            defaults: null,
            constraints: new { name = @"^[a-z]+$" }
        );

        config.Formatters.Remove(config.Formatters.XmlFormatter);
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;

        app.UseWebApi(config);
    }
}

Ниже приведены два вызова моих методов

[Route("{UserId}/{Key}/{Source}", Name = "GetToken")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key)
{
}

[Route("{Token}/{AcctNo}/{YearMonth}", Name = "GetInvoices")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
{
}

Если я закомментирую один из них, другой позвонят, но я не могу заставить его работать.

------------- Обновление ------------... изменили код следующим образом.

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

public IEnumerable<CustomListItem> Get()
{
    //            return new string[] { "value1", "value2" };
    return _listItems;
}

[Route("GetToken/{UserId}/{Key}/{Source}")]
[HttpGet]
public HttpResponseMessage GetToken(string UserId, string Key, string Source)
{
   ...
}

[Route("GetInvoices/{Token}/{AcctNo}/{YearMonth}")]
[HttpGet]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)
{
   ...
}

Даже с указанными выше изменениями всегда вызывается go к generi c Get (показан первый метод) Ниже приведены примеры звонки от почтальона (а также вставленные непосредственно в браузер) ??

http://localhost: 37788 / api / listitems / GetToken? UserId = Dshadle & Key = ABC & Source = Postman

http://localhost: 37788 / API / ListItems / GetInvoices Токен = ABC & AcctNo = 123 & годМесяц = ​​2019/12

Ответы [ 3 ]

1 голос
/ 29 января 2020

Похоже, вы хотите сопоставить api/ListItems/GetToken с конечной точкой GetToken(), и аналогично для GetInvoices. Из URL-адресов, которыми вы поделились, я предполагаю, что ваш контроллер называется ListItems.

На самом деле есть два способа сделать это sh. Какой бы метод вы ни выбрали, вам не нужно добавлять параметры в маршрут для показанных вами URL.

1. Маршрутизация атрибута

Удалите маршрут ApiByName из конфигурации. Затем вы можете украсить каждое действие полным путем (например, [Route("api/ListItems/GetToken")]), или , украсить контроллер с помощью [RoutePrefix("api/ListItems")] и украсить действие (я) с помощью Route("MyAction"). В приведенном ниже примере на контроллере используется RoutePrefix.

[RoutePrefix("api/ListItems")]
public class ListItemsController : ApiController
{     

  [Route("GetToken")]
  [HttpGet]
  public HttpResponseMessage GetToken(string UserId, string Key, string source)

  [Route("GetInvoices", Name = "GetInvoices")]
  [HttpGet]
  public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)

Если вы хотите, чтобы URL выглядел как ListItems/GetToken/123/ABC/Postman, просто добавьте параметры обратно в маршрут [Route("GetToken/{UserId}/{Key}/{Source}")], однако, вы разместили URL-адреса не соответствуют этому формату.

Свойство Name атрибута Route может работать не так, как вы ожидаете. На самом деле он используется для определения конечной точки внутри API, а не снаружи. Например, RedirectToRoute("GetInvoices") вернет перенаправление на конечную точку GetInvoices. Вам решать, нужно ли вам это включить или нет.

2. Обычная маршрутизация

Не использовать атрибут [Route] вообще.

Вместо этого добавьте следующие маршруты в конфигурацию маршрута API (благодаря ответу Дарина Димитрова ):

config.Routes.MapHttpRoute(
     name: "ApiById",
     routeTemplate: "api/{controller}/{id}",
     defaults: new { id = RouteParameter.Optional },
     constraints: new { id = @"^[0-9]+$" }
 );

config.Routes.MapHttpRoute(
    name: "ApiByAction",
    routeTemplate: "api/{controller}/{action}",
    defaults: new { action = "Get" }
);

Затем в контроллере используйте атрибут ActionName("MyAction") :

[HttpGet]
[ActionName("GetToken")]
public HttpResponseMessage GetToken(string UserId, string Key, string source)

[HttpGet]
[ActionName("GetInvoices")]
public HttpResponseMessage GetInvoices(string Token, string AcctNo, string YearMonth)

Я проверил оба эти метода со следующими URL-адресами:

// get list of items
http://localhost:28092/api/ListItems    

// get single item 
http://localhost:28092/api/ListItems/1  

// GetToken 
http://localhost:28092/api/ListItems/GetToken?userid=123&key=ABC&source=Postman

// GetInvoices
http://localhost:28092/api/ListItems/GetInvoices?token=ABC&acctno=1234&yearmonth=2019-12

Примечание 1 : я бы порекомендовал не с использованием / в качестве разделителя даты в URL-адресе, поскольку это может помешать маршрутизации, вместо этого используйте - или другой разделитель.

Примечание 2 : Параметры должны иметь значение, иначе каркас не сможет найти правильное действие. Если (некоторые из) параметры должны быть необязательными, укажите значения по умолчанию в сигнатуре метода, например, GetToken(string UserId, string Key, string source = "") (source здесь необязательно).


Однако, если вы хотите следовать Шаблон RESTful, тогда вы должны действительно структурировать свои конечные точки так, чтобы они соответствовали ресурсам, на которых они действуют. Вероятно, у вас должен быть контроллер Invoice, где вы можете выполнять Get, Post, Put, Delete и др. c для Invoice с. GetToken похоже, что он принадлежит другому контроллеру, если только он не связан с какими-либо счетами.

0 голосов
/ 29 января 2020

Ваш последний подход верен, но проблема здесь в том, что вы смешиваете 2 схемы.

Вы предоставляете эту настройку: [Route("GetInvoices/{Token}/{AcctNo}/{YearMonth}")]

А затем вы поворачиваетесь и тестируете, используя параметры запроса как это

/api/ListItems/GetInvoices?token=ABC&acctno=1234&yearmonth=2019-12

Но если вы посмотрите на свой атрибут Route, это указывает, что маршрут для этого действия должен быть сделан в пути. Вместо этого измените URL-адрес, который вы тестируете, в соответствии с путем:

/api/ListItems/GetInvoices/ABC/1234/2019-12

0 голосов
/ 29 января 2020

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

Если это не ваш случай, то самое простое решение - использовать параметры запроса

Поместить все 6 параметров в модель, передать его в качестве параметра для метода Get, помеченного [FromQuery] .

Примерно так:

[HttpGet] 
public async Task<IActionResult> Get([FromQuery] GetRequestParameters parameters)
{
   ... 
}

Таким образом, вы можете назвать это так:

GET https://your_url / api / your_controller? UserId = 123 & key = secret & source = somesource

Или

GET https://your_url / api / your_controller? token = abcd & accountNumber = secret & yearMonth = 202001

Осторожно, хотя, вы можете получать бессмысленные параметры, такие как токен, ключ и userId, которые не соответствуют вашим требованиям, поэтому вы должны проверить ввод

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...