当值类型可为空时,为什么ApiController返回空的Dictionary?

时间:2019-11-12 11:01:24

标签: c# asp.net-apicontroller

考虑此控制器:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class ExampleController : ControllerBase
    {
        [HttpGet]
        public Dictionary<string, int?> Get()
        {
            return new Dictionary<string, int?>()
            {
                {"foo", null},
                {"bar", 1}
            }; 
        }
    }
}

当我通过/example访问此控制器时,得到的响应仅包含{}。控制台中没有错误或警告。

但是,如果我删除?之后的int符号(即将可为空的整数更改为不可为空)并将null替换为0,它将返回字典应该。 decimalboolchar也会发生此问题。

应该注意的是,并非所有可空类型都以这种方式运行。例如,string可以正常工作。

已编辑的控制器:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class ExampleController : ControllerBase
    {
        [HttpGet]
        public Dictionary<string, int> Get()
        {
            return new Dictionary<string, int>()
            {
                {"foo", 0},
                {"bar", 1}
            }; 
        }
    }
}

响应:

{"foo":0,"bar":1}

int?List<int?>这样的返回类型都可以正常工作,只有字典有问题。

为什么会这样?谁该怪?

我正在使用.NET Core SDK (3.0.100),目标框架是netcoreapp3.0。我使用JetBrains Rider的GUI(File-> New...-> ASP.NET Core Web Application->类型:Web API)创建了此WebApplication。

2 个答案:

答案 0 :(得分:1)

我在ASP.Net Core 2.2中尝试了您的代码,它的工作使我相信这是新的Microsoft JSON序列化程序存在的问题,该序列化程序将取代以前使用的Newtonsoft。

我设法通过安装旧的Newtonsoft来解决此问题:

Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.0.0

并以此方式使用它:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
            .AddNewtonsoftJson();
}

只需将AddNewtonsoftJson添加到您的配置中。该方法可让您像往常一样设置JSON序列化程序,尽管我没有对此进行修正。

希望这会有所帮助。

答案 1 :(得分:1)

我将为可能遇到相同问题的其他人写一个答案:

Asp.Net Core 3.0随附的新内置JSON序列化程序中有一个众所周知的错误。它很难序列化可为空的值。不仅是字典中的可为空值,而且在嵌套对象中或必须执行字符串->可为空的转换时也是如此。它的设计方式可以显着提高性能,但显然它仍处于“行”状态。

所以现在最好使用Newtonsoft序列化程序:

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

services.AddNewtonsoftJson(options =>
{
    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});

正如奥利弗(Oliver)所指出的那样,此here

中存在一个错误