如何将整数列表发送到 web api 2 get 请求?
How to send a list of integers to web api 2 get request?
我正在尝试完成此任务,其中我需要将 ID(整数)列表发送到 Web api 2 get 请求。
所以我找到了一些示例 here 它甚至有一个示例项目,但它不起作用...
这是我的网站api方法代码:
[HttpGet]
[Route("api/NewHotelData/{ids}")]
public HttpResponseMessage Get([FromUri] List<int> ids)
{
// ids.Count is 0
// ids is empty...
}
这是我在 fiddler 中测试的 URL:
http://192.168.9.43/api/NewHotelData/?ids=1,2,3,4
但列表始终为空,并且 none 个 ID 正在传递给该方法。
似乎无法理解问题出在方法、URL 还是两者...
那么这是如何实现的呢?
按照评论中的建议使用自定义模型活页夹是执行此操作的正确方法。但是,您也可以像这样快速而简单地进行操作:
[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([FromUri] string ids)
{
var separated = ids.Split(new char[] { ',' });
List<int> parsed = separated.Select(s => int.Parse(s)).ToList();
}
首先,我拆分 uri ids
字符串,然后使用 Linq 将它们转换为整数列表。请注意,这缺少健全性检查,如果参数格式不正确,将会引发预期。
你这样称呼它:http://192.168.9.43/api/NewHotelData?ids=5,10,20
更新:就我个人而言,我认为将模型绑定器用于像这样简单的事情是过度工程化。您需要大量代码才能使事情变得如此简单。您将在模型绑定器中使用的代码实际上是 very similar,您只会获得更好的方法参数语法。如果您将整数解析包装到一个 try-catch 块中,并且 return 在格式错误的情况下显示适当的错误消息,我看不出为什么不使用这种方法。
[HttpGet]
[Route("api/getsomething")]
public HttpResponseMessage Get([FromUri] params int[] ids)
{
}
用法:http GET localhost:9000/api/getsomething?ids=1&ids=5&ids=9
显然这可以开箱即用:
http://192.168.9.43/api/NewHotelData/?ids=1&ids=2&ids=3&ids=4
也就是用不同的值重复参数名。但是,如果这些 ID 变得很大并且您必须包含很多 ID,可能会使 URL 太长,会发生什么情况?
不过,我认为将其设为 POST 请求并完成它会更简洁。您写道,您 需要 请求是 GET 而不是 POST,但为什么呢?在 AJAX 请求的上下文中,使用 POST 检索内容是完全可以接受的。
您需要自定义模型活页夹才能使其正常工作。这是您可以开始工作的简化版本:
public class CsvIntModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(key);
if (valueProviderResult == null)
{
return false;
}
var attemptedValue = valueProviderResult.AttemptedValue;
if (attemptedValue != null)
{
var list = attemptedValue.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).
Select(v => int.Parse(v.Trim())).ToList();
bindingContext.Model = list;
}
else
{
bindingContext.Model = new List<int>();
}
return true;
}
}
并以这种方式使用它(从路由中删除 {ids}
):
[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([ModelBinder(typeof(CsvIntModelBinder))] List<int> ids)
如果你想在路由中保留 {ids}
,你应该将客户端请求更改为:
api/NewHotelData/1,2,3,4
另一个选项(没有自定义模型活页夹)正在将获取请求更改为:
?ids=1&ids=2&ids=3
这可能太俗气了,但也可以这样做:
在您的 .NET class(模型)中:
public class TackyList
{
public IEnumerable<int> myIntList {get; set;}
}
在客户端你会做一个post即:{myIntList: [4,2,0]}
现在您控制器上的 action/method 看起来像:
public void myApiMethodThatDoesSomethingWith(TackyList tl)
{
// here you should be able to do something like:
if(tl != null && tl.Count > 0) // blah
}
我正在尝试完成此任务,其中我需要将 ID(整数)列表发送到 Web api 2 get 请求。
所以我找到了一些示例 here 它甚至有一个示例项目,但它不起作用...
这是我的网站api方法代码:
[HttpGet]
[Route("api/NewHotelData/{ids}")]
public HttpResponseMessage Get([FromUri] List<int> ids)
{
// ids.Count is 0
// ids is empty...
}
这是我在 fiddler 中测试的 URL:
http://192.168.9.43/api/NewHotelData/?ids=1,2,3,4
但列表始终为空,并且 none 个 ID 正在传递给该方法。
似乎无法理解问题出在方法、URL 还是两者...
那么这是如何实现的呢?
按照评论中的建议使用自定义模型活页夹是执行此操作的正确方法。但是,您也可以像这样快速而简单地进行操作:
[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([FromUri] string ids)
{
var separated = ids.Split(new char[] { ',' });
List<int> parsed = separated.Select(s => int.Parse(s)).ToList();
}
首先,我拆分 uri ids
字符串,然后使用 Linq 将它们转换为整数列表。请注意,这缺少健全性检查,如果参数格式不正确,将会引发预期。
你这样称呼它:http://192.168.9.43/api/NewHotelData?ids=5,10,20
更新:就我个人而言,我认为将模型绑定器用于像这样简单的事情是过度工程化。您需要大量代码才能使事情变得如此简单。您将在模型绑定器中使用的代码实际上是 very similar,您只会获得更好的方法参数语法。如果您将整数解析包装到一个 try-catch 块中,并且 return 在格式错误的情况下显示适当的错误消息,我看不出为什么不使用这种方法。
[HttpGet]
[Route("api/getsomething")]
public HttpResponseMessage Get([FromUri] params int[] ids)
{
}
用法:http GET localhost:9000/api/getsomething?ids=1&ids=5&ids=9
显然这可以开箱即用:
http://192.168.9.43/api/NewHotelData/?ids=1&ids=2&ids=3&ids=4
也就是用不同的值重复参数名。但是,如果这些 ID 变得很大并且您必须包含很多 ID,可能会使 URL 太长,会发生什么情况?
不过,我认为将其设为 POST 请求并完成它会更简洁。您写道,您 需要 请求是 GET 而不是 POST,但为什么呢?在 AJAX 请求的上下文中,使用 POST 检索内容是完全可以接受的。
您需要自定义模型活页夹才能使其正常工作。这是您可以开始工作的简化版本:
public class CsvIntModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(key);
if (valueProviderResult == null)
{
return false;
}
var attemptedValue = valueProviderResult.AttemptedValue;
if (attemptedValue != null)
{
var list = attemptedValue.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).
Select(v => int.Parse(v.Trim())).ToList();
bindingContext.Model = list;
}
else
{
bindingContext.Model = new List<int>();
}
return true;
}
}
并以这种方式使用它(从路由中删除 {ids}
):
[HttpGet]
[Route("api/NewHotelData")]
public HttpResponseMessage Get([ModelBinder(typeof(CsvIntModelBinder))] List<int> ids)
如果你想在路由中保留 {ids}
,你应该将客户端请求更改为:
api/NewHotelData/1,2,3,4
另一个选项(没有自定义模型活页夹)正在将获取请求更改为:
?ids=1&ids=2&ids=3
这可能太俗气了,但也可以这样做:
在您的 .NET class(模型)中:
public class TackyList
{
public IEnumerable<int> myIntList {get; set;}
}
在客户端你会做一个post即:{myIntList: [4,2,0]}
现在您控制器上的 action/method 看起来像:
public void myApiMethodThatDoesSomethingWith(TackyList tl)
{
// here you should be able to do something like:
if(tl != null && tl.Count > 0) // blah
}