【问题标题】:How to make ASP.NET to stop interpret null as string如何使 ASP.NET 停止将 null 解释为字符串
【发布时间】:2017-05-04 13:19:20
【问题描述】:

我有一个 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 等)不能以这种方式处理空值。

如何让 ASP.NET 将'null' 解释为null

更新:查询字符串可以包含多个标识符,例如:

GET /tasks?assignees=1&assignees=2&assignees=null

Upd2: JQuery 将数组中的 null 转换为空字符串,ASP.NET 将它们解释为 null。所以问题是关于从 Angular 1.6 调用 WebAPI ($HttpParamSerializerProvider)

Upd3:我知道解决方法,但我不要求他们。我想要针对特定​​问题的解决方案:

  • 这是一个 GET 方法
  • 方法接受来自 Uri 的列表
  • 列表可以包含null
  • 应该是List&lt;int?&gt;,因为API文档是自动生成的,我不想看到文本数组作为参数类型
  • 默认情况下,ASP.NET 期望空字符串为空值(JQuery.param 以这种方式工作)
  • 但某些客户端库(例如 Angular)不会将 null 数组项转换为空字符串

【问题讨论】:

  • 在您的参数列表中,如果您可以将参数更改为字符串并检查null 为字符串,然后将它们解析为各自的数据类型,这种方式是否适合您?跨度>
  • 有点超出我的理解,如果这没有意义,请见谅。 $.map() 有帮助吗?我还搜索了您所说的内容-“JQuery 将数组中的空值转换为空字符串”并得到了一些可能不错的(??)结果。
  • @Webruster,我使用自动 API 文档生成,我想在这里查看数字(不是字符串)列表。 @wazz,我可以在前端做所有事情,但是 API 是公共的并且在不同的其他客户端中使用的问题。所以我想让 ASP.NET 将'null''' 解释为null
  • @Artem 在 DB 的末尾,它将仅存储为数字,但从客户端到控制器,它将是字符串,在控制器中,它将被解析为相应的 DataType,这不会是冲突自动生成 api 文档
  • @Webruster,我说的是 API 文档,DB 根本与我的问题无关。

标签: asp.net asp.net-web-api query-string


【解决方案1】:

您可以为此特定类型创建自定义模型绑定,继承自 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.
}

如需更多参考,请查看Custom Model Binders 上的此链接。 希望,这可以解决您的问题。谢谢

【讨论】:

  • 这个例子是针对 MVC 控制器的,在问题的开头我写了“我有一个 Web API 方法”。但是谢谢,我会尝试将此解决方案应用于 Web API。
【解决方案2】:

最后,我找到了使用自定义值提供者的解决方案:

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)
{
}

【讨论】:

    猜你喜欢
    • 2013-09-27
    • 2016-02-21
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 2019-05-18
    • 1970-01-01
    • 2018-05-22
    • 2010-09-27
    相关资源
    最近更新 更多