Web Api属性路由中的可选参数

时间:2014-04-01 06:43:22

标签: c# asp.net asp.net-web-api asp.net-web-api-routing

我想处理以下API调用的POST:

/v1/location/deviceid/appid

附加参数来自Post-Body。

这对我来说都很好。现在我想通过允许“deviceid”和/或“appid”和/或BodyData为null来扩展我的代码:

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

这三个网址应采用相同的路由。

我的第一种方法(需要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处理“添加新位置”。

我想在错误的数据上发送我自己的异常或错误消息。即使呼叫缺少值。在这种情况下,我希望能够决定通过我的代码抛出异常或设置默认值。

4 个答案:

答案 0 :(得分:147)

对于像/v1/location/1234这样的传入请求,您可以想象Web API很难自动判断对应于'1234'的段的值是否与appid相关而不是到deviceid

我认为你应该改变你的路线模板 [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]然后解析deiveOrAppid以找出ID的类型。

此外,您还需要使路径模板中的段可选,否则段将被视为必需。在这种情况下请注意?字符。 例如: [Route("v1/location/{deviceOrAppid?}", Name = "AddNewLocation")]

答案 1 :(得分:40)

另一个信息:如果您想使用路径约束,想象您希望强制该参数具有 int 数据类型,那么您需要使用以下语法:

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

字符始终位于最后} 字符之前

有关详细信息,请参阅:Optional URI Parameters and Default Values

答案 2 :(得分:10)

将我的评论转换为答案以补充@Kiran Chala的答案,因为它似乎对观众有帮助 -

当我们使用?字符在操作uri中将参数标记为可选时,我们必须为方法签名中的参数提供默认值,如下所示:

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

答案 3 :(得分:3)

好的,我的互联网研究失败了,我继续我的方式,因为公认的解决方案不适用于 dotnet core 3.1。 所以这是我的解决方案,遵循 this doc

[HttpPost]
[Route("{name}")]
[Route("{name}/parent/{parentId}")]
public async Task<IActionResult> PostSomething(string name, Guid? parentId = null)
{
    return Ok(await Task.FromResult(new List<string>()));
}

通过这种方式,许多路由都转到这个单一的 API 函数