我有一个ASP。NET Web API(版本4)REST服务,我需要传递一个整数数组。
下面是我的动作方法:
public IEnumerable<Category> GetCategories(int[] categoryIds){
// code to retrieve categories from database
}
这是我试过的网址:
/Categories?categoryids=1,2,3,4
我有一个ASP。NET Web API(版本4)REST服务,我需要传递一个整数数组。
下面是我的动作方法:
public IEnumerable<Category> GetCategories(int[] categoryIds){
// code to retrieve categories from database
}
这是我试过的网址:
/Categories?categoryids=1,2,3,4
当前回答
我已经创建了一个自定义模型绑定器,它将任何逗号分隔的值(仅为原语、十进制、浮点数、字符串)转换为相应的数组。
public class CommaSeparatedToArrayBinder<T> : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
Type type = typeof(T);
if (type.IsPrimitive || type == typeof(Decimal) || type == typeof(String) || type == typeof(float))
{
ValueProviderResult val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (val == null) return false;
string key = val.RawValue as string;
if (key == null) { bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Wrong value type"); return false; }
string[] values = key.Split(',');
IEnumerable<T> result = this.ConvertToDesiredList(values).ToArray();
bindingContext.Model = result;
return true;
}
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Only primitive, decimal, string and float data types are allowed...");
return false;
}
private IEnumerable<T> ConvertToDesiredArray(string[] values)
{
foreach (string value in values)
{
var val = (T)Convert.ChangeType(value, typeof(T));
yield return val;
}
}
}
以及如何在Controller中使用:
public IHttpActionResult Get([ModelBinder(BinderType = typeof(CommaSeparatedToArrayBinder<int>))] int[] ids)
{
return Ok(ids);
}
其他回答
我最初使用@Mrchief这个解决方案很多年了(它工作得很好)。但是当我将Swagger添加到我的API文档项目时,我的终点并没有显示出来。
这花了我一段时间,但这是我想到的。它与Swagger一起工作,你的API方法签名看起来更干净:
最后你可以做到:
// GET: /api/values/1,2,3,4
[Route("api/values/{ids}")]
public IHttpActionResult GetIds(int[] ids)
{
return Ok(ids);
}
WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Allow WebApi to Use a Custom Parameter Binding
config.ParameterBindingRules.Add(descriptor => descriptor.ParameterType == typeof(int[]) && descriptor.ActionDescriptor.SupportedHttpMethods.Contains(HttpMethod.Get)
? new CommaDelimitedArrayParameterBinder(descriptor)
: null);
// Allow ApiExplorer to understand this type (Swagger uses ApiExplorer under the hood)
TypeDescriptor.AddAttributes(typeof(int[]), new TypeConverterAttribute(typeof(StringToIntArrayConverter)));
// Any existing Code ..
}
}
创建一个新类:CommaDelimitedArrayParameterBinder.cs
public class CommaDelimitedArrayParameterBinder : HttpParameterBinding, IValueProviderParameterBinding
{
public CommaDelimitedArrayParameterBinder(HttpParameterDescriptor desc)
: base(desc)
{
}
/// <summary>
/// Handles Binding (Converts a comma delimited string into an array of integers)
/// </summary>
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
HttpActionContext actionContext,
CancellationToken cancellationToken)
{
var queryString = actionContext.ControllerContext.RouteData.Values[Descriptor.ParameterName] as string;
var ints = queryString?.Split(',').Select(int.Parse).ToArray();
SetValue(actionContext, ints);
return Task.CompletedTask;
}
public IEnumerable<ValueProviderFactory> ValueProviderFactories { get; } = new[] { new QueryStringValueProviderFactory() };
}
创建一个新类:StringToIntArrayConverter.cs
public class StringToIntArrayConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
}
注:
https://stackoverflow.com/a/47123965/862011为我指明了正确的方向 Swagger只是在使用[Route]属性时未能选择我的逗号分隔的端点
除了使用自定义ModelBinder,还可以使用带有TypeConverter的自定义类型。
[TypeConverter(typeof(StrListConverter))]
public class StrList : List<string>
{
public StrList(IEnumerable<string> collection) : base(collection) {}
}
public class StrListConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value == null)
return null;
if (value is string s)
{
if (string.IsNullOrEmpty(s))
return null;
return new StrList(s.Split(','));
}
return base.ConvertFrom(context, culture, value);
}
}
它的优点是使Web API方法的参数非常简单。你甚至不需要指定[FromUri]。
public IEnumerable<Category> GetCategories(StrList categoryIds) {
// code to retrieve categories from database
}
这个例子是一个字符串列表,但你可以使用categoryIds.Select(int.Parse)或简单地编写一个IntList代替。
你可以尝试这段代码来获取逗号分隔的值/一个值数组来从webAPI返回JSON
public class CategoryController : ApiController
{
public List<Category> Get(String categoryIDs)
{
List<Category> categoryRepo = new List<Category>();
String[] idRepo = categoryIDs.Split(',');
foreach (var id in idRepo)
{
categoryRepo.Add(new Category()
{
CategoryID = id,
CategoryName = String.Format("Category_{0}", id)
});
}
return categoryRepo;
}
}
public class Category
{
public String CategoryID { get; set; }
public String CategoryName { get; set; }
}
输出:
[
{"CategoryID":"4","CategoryName":"Category_4"},
{"CategoryID":"5","CategoryName":"Category_5"},
{"CategoryID":"3","CategoryName":"Category_3"}
]
所有其他解决方案都需要大量的工作。我试图在HttpGet方法参数中使用IEnumerable<long>或long[],但我认为没有必要做所有的工作,只是为了使处理程序方法参数的签名long[]。我最终只是把它变成字符串,然后在处理程序中把它分开。我只说了一句。
public async Task<IActionResult> SomeHandler(string idsString)
{
var ids = idsString.Split(',').Select(x => long.Parse(x));
现在你可以传递这些数字
.../SomeHandler?idsString=123,456,789,012
如果有人需要-通过POST而不是FromUri来实现相同或类似的事情(如删除),使用FromBody和客户端(JS/jQuery)格式参数为$。参数({":categoryids}, true)
c#:
public IHttpActionResult Remove([FromBody] int[] categoryIds)
jQuery:
$.ajax({
type: 'POST',
data: $.param({ '': categoryids }, true),
url: url,
//...
});
关于$。Param ({": categoryids}, true)是。net期望post正文包含urlencoded的值,如=1&=2&=3,不带参数名,不带括号。