Parâmetros opcionais no roteamento de atributo da API da Web

89

Quero lidar com o POST da seguinte API-Call:

/v1/location/deviceid/appid

Parâmetros adicionais estão vindo do Post-Body.

Tudo isso funciona bem para mim. Agora quero estender meu código permitindo que "deviceid" e / ou "appid" e / ou BodyData sejam nulos:

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

Esses 3 URLs devem responder pela mesma rota.

Minha primeira abordagem (BodyData obrigatório):

[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);
}

Isso não funciona e retorna um erro de compilação:

"Parâmetros opcionais devem estar no final"

Próxima tentativa:

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

Agora minha função AddNewLocation () sempre obtém um BodyData=null- mesmo se a chamada enviar o Corpo.

Finalmente, defino todos os 3 parâmetros opcionais:

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

Não trabalhe:

O parâmetro opcional BodyDatanão é compatível com FormatterParameterBinding.

Por que eu quero uma solução com parâmetros opcionais? Meu controlador lida apenas com a "adição de um novo local" por meio de um POST.

Quero enviar com dados errados minhas próprias exceções ou mensagens de erro. Mesmo se a chamada tiver valores ausentes. Nesse caso, quero poder decidir lançar uma exceção ou definir padrões pelo meu código.

Oliver Apel
fonte

Respostas:

174

Para uma solicitação de entrada /v1/location/1234, como você pode imaginar, seria difícil para a API da Web descobrir automaticamente se o valor do segmento correspondente a '1234' está relacionado a appide não a deviceid.

Acho que você deve alterar seu modelo de rota para ser semelhante [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]e, em seguida, analisar o deiveOrAppidpara descobrir o tipo de id.

Além disso, você precisa tornar os segmentos no próprio modelo de rota opcionais, caso contrário, os segmentos são considerados necessários. Observe o ?personagem neste caso. Por exemplo: [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]

Kiran Challa
fonte
55
?dentro do modelo de rota é o que eu estava procurando. +1
Kal_Torak
4
Eu não diria que "deviceOrAppId" é a melhor escolha de design. Acho que a API deve sempre saber por definição o que estará recebendo, se possível.
Niels Brinch
13
Apenas para informação - Quando marcamos um parâmetro como opcional na ação uri usando ?caractere, devemos fornecer valores padrão para os parâmetros na assinatura do método, por exemplo, MyMethod (string name = "someDefaultValue", int? Id = null).
RBT
@RBT você é um verdadeiro MVP, fiquei perplexo por um minuto. Obrigado!
sm
1
Legal. Que bom que ajudou você @sm. Transformei meu comentário em uma resposta para uma melhor visibilidade, pois parece útil. Será um add-on para a postagem de Kiran.
RBT
45

Outra informação: se você quiser usar uma Restrição de Rota , imagine que deseja forçar que o parâmetro tenha o tipo de dados int , então você precisa usar esta sintaxe:

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

O ? personagem é colocado sempre antes do último } caráter

Para obter mais informações, consulte: Parâmetros de URI opcionais e valores padrão

Tiago Ferreira
fonte
18

Converter meu comentário em uma resposta para complementar a resposta de @Kiran Chala, pois parece útil para o público-

Quando marcamos um parâmetro como opcional na ação uri usando ?caractere, devemos fornecer valores padrão para os parâmetros na assinatura do método, conforme mostrado abaixo:

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

RBT
fonte
Eu ia comentar o mesmo.
Jnr