我有一个Web API方法:
public List<Task> GetTasks([FromUri] TaskFilter filter)
{
}
该方法具有无效标识符列表的参数:
public class TaskFilter
{
public IList<int?> Assignees { get; set; }
}
当我称呼它:
GET /tasks?assignees=null
服务器返回错误:
{
"message":"The request is invalid.",
"modelState": {
"assignees": [ "The value 'null' is not valid for Nullable`1." ]
}
}
它仅在我传递空字符串时才有效:
GET /tasks?assignees=
但是标准查询字符串转换器(来自 jQuery, Angular等(不能以这种方式使用nulls。
如何使ASP.NET解释'null'
为null
?
upd:查询字符串可以包含多个标识符,例如:
GET /tasks?assignees=1&assignees=2&assignees=null
upd2: jQuery将数组中的nulls转换为空字符串,而ASP.NET将其解释为空字符串。因此,问题是关于从Angular 1.6($HttpParamSerializerProvider
(调用WebAPI
upd3:我知道解决方法,但我不要求它们。我想要解决特定问题的解决方案:
- 这是一个获取方法
- 方法接受uri 的列表
- 列表可以包含
null
值 - 应该是
List<int?>
,因为API文档是自动生成的,我不想将文本数组作为参数类型 - 默认情况下,ASP.NET期望空值空字符串(
JQuery.param
以这种方式工作( - 但是某些客户端库(例如Angular(不会将
null
数组项转换为空字符串
您可以为此特定类型创建一个自定义模型,从defaultmodelbinder继承,用于示例:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
public class TaskFilterBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, System.Web.Mvc.ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
var assignees = request.QueryString["assignees"];
if (assignees == "null") // check if assignees is null (string) then return NULL
return null;
return assignees;
}
}
最终,我们需要告知控制器我们希望使用的绑定。我们可以使用属性指定
[ModelBinder(typeof(TaskfilterBinder((]
如下:
public List<Task> GetTasks([FromUri(ModelBinder=typeof(TaskFilterBinder))] TaskFilter filter)
{
// Do your stuff.
}
有关更多参考,请在自定义模型绑定器上查看此链接。希望,这可以解决您的问题。谢谢
最后,我使用自定义值提供商找到了一个解决方案:
using System;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ValueProviders;
using System.Web.Http.ValueProviders.Providers;
using System.Globalization;
using System.Net.Http;
using System.Web.Http.ModelBinding;
public sealed class NullableValueProviderAttribute : ModelBinderAttribute
{
private readonly string[] _nullableColumns;
public NullableValueProviderAttribute(params string[] nullableColumns)
{
_nullableColumns = nullableColumns;
}
public override IEnumerable<ValueProviderFactory> GetValueProviderFactories(HttpConfiguration configuration)
{
return new ValueProviderFactory[] { new NullableValueProviderFactory(_nullableColumns) };
}
}
public class NullableValueProviderFactory : ValueProviderFactory, IUriValueProviderFactory
{
private readonly string[] _nullableColumns;
public NullableValueProviderFactory(string[] nullableColumns)
{
_nullableColumns = nullableColumns;
}
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
{
return new NullableQueryStringValueProvider(actionContext, CultureInfo.InvariantCulture, _nullableColumns);
}
}
public class NullableQueryStringValueProvider : NameValuePairsValueProvider
{
private static readonly string[] _nullValues = new string[] { "null", "undefined" };
private static IEnumerable<KeyValuePair<string, string>> GetQueryNameValuePairs(HttpRequestMessage request, string[] nullableColumns)
{
foreach (var pair in request.GetQueryNameValuePairs())
{
var isNull = Array.IndexOf(nullableColumns, pair.Key) >= 0 && Array.IndexOf(_nullValues, pair.Value) >= 0;
yield return isNull ? new KeyValuePair<string, string>(pair.Key, "") : pair;
};
}
public NullableQueryStringValueProvider(HttpActionContext actionContext, CultureInfo culture, string[] nullableColumns) :
base(GetQueryNameValuePairs(actionContext.ControllerContext.Request, nullableColumns), culture)
{ }
}
并在Web API操作中指定它:
public List<Task> GetTasks([NullableValueProvider("assignees")] TaskFilter filter)
{
}