为啥 WCF/JSON 不为 null 返回值返回“null”?

Posted

技术标签:

【中文标题】为啥 WCF/JSON 不为 null 返回值返回“null”?【英文标题】:Why doesn't WCF/JSON return `null` for a null return value?为什么 WCF/JSON 不为 null 返回值返回“null”? 【发布时间】:2016-12-28 04:29:15 【问题描述】:

根据JSON spec,表示空值的正确方法是文字null

如果是这样,为什么 WCF 返回一个空响应而不是 null?这是一个错误还是这种行为记录在某处?

完整的复制示例:

using System;
using System.ServiceModel;
using System.ServiceModel.Web;

[ServiceContract()]
public class Service1

    [OperationContract(), WebGet(ResponseFormat = WebMessageFormat.Json)]
    public string GetSomeString()  return "SomeString"; 

    [OperationContract(), WebGet(ResponseFormat = WebMessageFormat.Json)]
    public string GetNull()  return null; 


public class Host

    public static void Main()
    
        // Very simple WCF server
        var host = new WebServiceHost(typeof(Service1), new Uri("http://localhost:8000/"));
        host.AddServiceEndpoint(typeof(Service1), new WebHttpBinding() 
            HostNameComparisonMode = HostNameComparisonMode.Exact
        , "");

        host.Open();
        Console.WriteLine("Service is running, press enter to quit...");
        Console.ReadLine();
        host.Close();
    

预期结果:

$ curl http://localhost:8000/GetSomeString && echo
"SomeString"
$ curl http://localhost:8000/GetNull && echo
null
$

实际结果:

$ curl http://localhost:8000/GetSomeString && echo
"SomeString"
$ curl http://localhost:8000/GetNull && echo

$

【问题讨论】:

因为空值可以用许多不同的方式表示。有关更多信息,请参阅此帖子:***.com/questions/21120999/representing-null-in-json @TomRedfern:该帖子的公认答案还声称,null 是根据 JSON 规范应该表示 null 的方式。我的问题是为什么 WCF 偏离规范。 鉴于recent answer,我想知道您的服务是否真的以Content-Type: application/json 响应? @GSerg:好问题,我刚刚检查过:它以 Content-Type: application/json; charset=utf-8 响应 GetSomeString,而没有针对 GetNull 的 Content-Type 标头。正如我在答案下面评论的那样,我相信来自 JSON 主页的引用仅总结了除原始值之外可用的数据结构,而不是将 JSON“基本元素”限制为两者之一。 相关讨论:***.com/q/18419428/11683。我认为,除了公认的答案之外,问题used to fail validation 和现在的they pass 中列出的原语特别相关,WCF 来自它们失败的时代。 【参考方案1】:

您的 link 到 json 规范包括以下有趣的行:

JSON 建立在两种结构之上:

    名称/值对的集合。在各种语言中,这被实现为对象、记录、结构、字典、哈希表、键控 列表或关联数组。

    值的有序列表。在大多数语言中,这被实现为数组、向量、列表或序列。

因此,据我了解,您的返回类型不符合规范。

public string GetNull() return null; 也不是

也不是public string GetSomeString() return "SomeString";

要满足规范,您必须更改它们以匹配 #1 或 #2。

    使用了一个结构。 public struct structWithNullpublic object resp; 默认值为空,所以public structWithNull GetNull() return new structWithNull() ; 返回:

    使用了大小为 1 的数组。 public object[] GetNullArray() return new object[1] ; 。默认值再次为空;它返回:

在我看来,JSON 是基于封装数据的,例如 XML,其中始终需要父节点。所以我想没有其他解决方案可以使用结构/类(#1)或数组(#2)。

更新:

我在这里找到了线索:rfc7159

请注意,某些先前的 JSON 规范将 JSON 文本限制为对象或数组。仅生成需要 JSON 文本的对象或数组的实现将是可互操作的,因为所有实现都将接受这些作为符合标准的 JSON 文本。

如果我理解正确,你是对的,今天应该返回 null,因为它是一个原始类型,但不会因为主要关注点可能是唯一基于对象和数组的版本的旧指定行为。

最后我相信只有微软才能完全回答这个问题。

【讨论】:

这是一个有趣的观点,但我相信您对 JSON 主页的引用确实暗示有效的 JSON 文本必须有一个对象或数组作为基本元素。如果我们查看从页面链接的 ECMA-404 PDF,我们会看到 any JSON 值是有效的 JSON 文本。引用(强调我的):JSON 文本是由符合 JSON value 语法的 Unicode 代码点形成的标记序列。 [...] JSON 值可以是对象、数组、数字、字符串、truefalsenull 因此,null、@ 987654336@ 和 "abc" 将是有效的 JSON 文本,但 `` (empty) 不会。【参考方案2】:

在我看来,WCF 或其他方式是数据传输合同,所有数据都基于字符串。只是你如何收缩字符串形式的区别。 这个方法只是返回一个字符串,不管是什么格式只有客户端才能获取数据,所以不需要是json格式。 如果只返回字符串"null" 代表null 如果我想返回字符串"null" 而不是null 怎么办。会很迷茫。当然你可以用ESC字符来解决它。也许他们认为没有比这更好的了。 如果客户端使用json格式的数据,你只返回一个字符串"null",然后客户端反序列化得到一个null,一切正常。无论如何,返回什么并不重要,重要的是如何收缩数据格式。

【讨论】:

是的,唯一重要的是发送者和接收者知道消息的含义。【参考方案3】:

如果您希望在 wcf 响应中以 json 格式返回实际的空值,您应该定义一个数据契约并在不初始化的情况下返回它

[DataContract] 
public class Employee 
 
[DataMember]
public string id  get; set; 

现在在你的操作合同中像这样返回它

[OperationContract(), WebGet(ResponseFormat = WebMessageFormat.Json)]
public string GetNull()  return new Employee(); 

然后您将在您的 json 响应中为空值。

希望对你有帮助

【讨论】:

以上是关于为啥 WCF/JSON 不为 null 返回值返回“null”?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 skimage.imread() 不为我的 bmp 返回 RGB 值?

mysql 统计值为NULL不为0的问题

scala - 为啥map.size在地图不为空时返回0

为啥函数返回的值总是 null 或 undefined?

为啥我从 Dapper 返回的对象具有 null 和默认属性值?

hibernate多表联合查询返回的list没有数据,但list.isEmpty()判断为啥不为真