Необязательные параметры в маршрутизации атрибутов веб-API

93

Я хочу обработать POST следующего API-вызова:

/v1/location/deviceid/appid

Дополнительные параметры поступают из Post-Body.

У меня все работает нормально. Теперь я хочу расширить свой код, разрешив "deviceid" и / или "appid" и / или BodyData иметь значение null:

/v1/location/deviceid
/v1/location/appid
/v1/location/

Эти 3 URL-адреса должны отвечать одним и тем же маршрутом.

Мой первый подход (требуется BodyData):

[Route("v1/location/{deviceid}/{appid}", Name = "AddNewLocation")]
public location_fromuser Post(string deviceid = null, string appid = null, [FromBody] location_fromuser BodyData)
{
    return repository.AddNewLocation(deviceid, appid, BodyData);
}

Это не работает и возвращает ошибку компиляции:

"необязательные параметры должны быть в конце"

Следующая попытка:

[Route("v1/location/{deviceid}/{appid}", Name = "AddNewLocation")]
public location_fromuser Post([FromBody] location_fromuser BodyData, string deviceid = null, string appid = null)

Теперь моя функция AddNewLocation () всегда получает BodyData=null- даже если вызов отправляет Body.

Наконец, я установил все 3 параметра необязательными:

[Route("v1/location/{deviceid}/{appid}", Name = "AddNewLocation")]
public location_fromuser Post(string deviceid = null, string appid = null, [FromBody location_fromuser BodyData = null)

Не работает:

Необязательный параметр BodyDataне поддерживаетсяFormatterParameterBinding .

Почему мне нужно решение с дополнительными параметрами? Мой контроллер обрабатывает только «добавление нового местоположения» через POST.

Я хочу отправлять на неправильные данные мои собственные исключения или сообщения об ошибках. Даже если в вызове отсутствуют значения. В этом случае я хочу иметь возможность принять решение о создании исключения или установке значений по умолчанию с помощью моего кода.

Оливер Апель
источник

Ответы:

182

Для входящего запроса, например /v1/location/1234, как вы понимаете, веб-API будет сложно автоматически определить, связано ли значение сегмента, соответствующего «1234», с, appidа не с deviceid.

Я думаю, вам следует изменить свой шаблон маршрута, чтобы он был похож, [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]а затем проанализировать его, deiveOrAppidчтобы выяснить тип идентификатора.

Также вам необходимо сделать сегменты в самом шаблоне маршрута необязательными, иначе сегменты будут считаться необходимыми. Обратите внимание на ?характер в этом случае. Например: [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]

Киран Чалла
источник
58
?внутри шаблона маршрута это то, что я искал. +1
Kal_Torak
4
Я бы не сказал, что deviceOrAppId - лучший выбор дизайна. Я думаю, что API всегда по определению должен знать, что он будет получать, если это вообще возможно.
Нильс Бринч
14
Только для информации - когда мы отмечаем параметр как необязательный в uri действия с помощью ?символа, мы должны предоставить значения по умолчанию для параметров в сигнатуре метода, например MyMethod (string name = "someDefaultValue", int? Id = null).
RBT
@RBT, ты настоящий MVP, я на минуту застрял. Спасибо!
sm
1
Круто. Рад, что это помогло вам @sm. Я превратил свой комментарий в ответ для большей наглядности, поскольку он кажется полезным. Это будет дополнение к сообщению Кирана.
RBT
47

Другая информация: если вы хотите использовать ограничение маршрута , представьте, что вы хотите, чтобы этот параметр имел тип данных int , тогда вам нужно использовать этот синтаксис:

[Route("v1/location/**{deviceOrAppid:int?}**", Name = "AddNewLocation")]

? символ всегда ставится перед последним } символом

Для получения дополнительной информации см .: Дополнительные параметры URI и значения по умолчанию.

Тьяго Феррейра
источник
18

Преобразование моего комментария в ответ, чтобы дополнить ответ @Kiran Chala, поскольку он кажется полезным для аудитории -

Когда мы отмечаем параметр как необязательный в uri действия с помощью ?символа, мы должны предоставить значения по умолчанию для параметров в сигнатуре метода, как показано ниже:

MyMethod(string name = "someDefaultValue", int? Id = null)

RBT
источник
Я собирался прокомментировать то же самое.
Jnr