我有一个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
当前回答
我最近遇到了这个需求,我决定实现一个ActionFilter来处理这个问题。
public class ArrayInputAttribute : ActionFilterAttribute
{
private readonly string _parameterName;
public ArrayInputAttribute(string parameterName)
{
_parameterName = parameterName;
Separator = ',';
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.ContainsKey(_parameterName))
{
string parameters = string.Empty;
if (actionContext.ControllerContext.RouteData.Values.ContainsKey(_parameterName))
parameters = (string) actionContext.ControllerContext.RouteData.Values[_parameterName];
else if (actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName] != null)
parameters = actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName];
actionContext.ActionArguments[_parameterName] = parameters.Split(Separator).Select(int.Parse).ToArray();
}
}
public char Separator { get; set; }
}
我像这样应用它(注意,我使用'id',而不是'ids',因为这是如何在我的路由中指定的):
[ArrayInput("id", Separator = ';')]
public IEnumerable<Measure> Get(int[] id)
{
return id.Select(i => GetData(i));
}
public url是:
/api/Data/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);
}
简单的方法发送数组参数到web api
API
public IEnumerable<Category> GetCategories([FromUri]int[] categoryIds){
// code to retrieve categories from database
}
Jquery:发送JSON对象作为请求参数
$.get('api/categories/GetCategories',{categoryIds:[1,2,3,4]}).done(function(response){
console.log(response);
//success response
});
它会生成你的请求URL . . / api /类别/ GetCategories吗?categoryid = 1 &categoryids = 2 &categoryids = 3 &categoryids = 4
我是这样处理这个问题的。
我使用了一个post消息到api,将整数列表作为数据发送。
然后我以ienumerable的形式返回数据。
发送代码如下:
public override IEnumerable<Contact> Fill(IEnumerable<int> ids)
{
IEnumerable<Contact> result = null;
if (ids!=null&&ids.Count()>0)
{
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:49520/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
String _endPoint = "api/" + typeof(Contact).Name + "/ListArray";
HttpResponseMessage response = client.PostAsJsonAsync<IEnumerable<int>>(_endPoint, ids).Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
result = JsonConvert.DeserializeObject<IEnumerable<Contact>>(response.Content.ReadAsStringAsync().Result);
}
}
}
catch (Exception)
{
}
}
return result;
}
接收代码如下:
// POST api/<controller>
[HttpPost]
[ActionName("ListArray")]
public IEnumerable<Contact> Post([FromBody]IEnumerable<int> ids)
{
IEnumerable<Contact> result = null;
if (ids != null && ids.Count() > 0)
{
return contactRepository.Fill(ids);
}
return result;
}
它只适用于一张唱片或多张唱片。fill是一个使用DapperExtensions的重载方法:
public override IEnumerable<Contact> Fill(IEnumerable<int> ids)
{
IEnumerable<Contact> result = null;
if (ids != null && ids.Count() > 0)
{
using (IDbConnection dbConnection = ConnectionProvider.OpenConnection())
{
dbConnection.Open();
var predicate = Predicates.Field<Contact>(f => f.id, Operator.Eq, ids);
result = dbConnection.GetList<Contact>(predicate);
dbConnection.Close();
}
}
return result;
}
这允许您从组合表(id列表)中获取数据,然后从目标表中返回您真正感兴趣的记录。
您也可以对视图执行相同的操作,但这为您提供了更多的控制和灵活性。
此外,查询字符串中不会显示您正在从数据库中查找的内容的详细信息。您也不必从csv文件进行转换。
当你使用像web api这样的工具时,你必须记住这一点。X接口是指get、put、post、delete、head等函数有一般用途,但不限于那种用途。
因此,虽然post通常用于web api接口中的创建上下文,但它并不仅限于此用途。它是一个常规的html调用,可以用于html实践允许的任何目的。
此外,正在发生的事情的细节对我们这些天听到太多的“窥探的眼睛”来说是隐藏的。
web api中命名约定的灵活性2。X接口和使用常规的网络调用意味着你向web API发送了一个调用,这会误导窥探者认为你实际上在做其他事情。例如,您可以使用“POST”来真正检索数据。
我最初使用@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]属性时未能选择我的逗号分隔的端点
我最近遇到了这个需求,我决定实现一个ActionFilter来处理这个问题。
public class ArrayInputAttribute : ActionFilterAttribute
{
private readonly string _parameterName;
public ArrayInputAttribute(string parameterName)
{
_parameterName = parameterName;
Separator = ',';
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ActionArguments.ContainsKey(_parameterName))
{
string parameters = string.Empty;
if (actionContext.ControllerContext.RouteData.Values.ContainsKey(_parameterName))
parameters = (string) actionContext.ControllerContext.RouteData.Values[_parameterName];
else if (actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName] != null)
parameters = actionContext.ControllerContext.Request.RequestUri.ParseQueryString()[_parameterName];
actionContext.ActionArguments[_parameterName] = parameters.Split(Separator).Select(int.Parse).ToArray();
}
}
public char Separator { get; set; }
}
我像这样应用它(注意,我使用'id',而不是'ids',因为这是如何在我的路由中指定的):
[ArrayInput("id", Separator = ';')]
public IEnumerable<Measure> Get(int[] id)
{
return id.Select(i => GetData(i));
}
public url是:
/api/Data/1;2;3;4
您可能必须对其进行重构以满足您的特定需求。