为什么WCF/JSON不会返回null值作为空的返回值?

16
根据JSON规范,表示null值的正确方式是使用字面量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

$

由于空值可以用许多不同的方式表示。有关更多信息,请参阅此帖子:https://dev59.com/aWEi5IYBdhLWcg3wnNTA - tom redfern
鉴于最近的回答,我想知道你的服务是否实际响应 Content-Type: application/json - GSerg
1
相关讨论:https://dev59.com/5WMl5IYBdhLWcg3wa2bW。我认为除了被接受的答案之外,问题中列出的原语[曾经无法通过验证](http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json#comment27059099_18419428),现在它们已经[通过了](http://jsonlint.com/),而WCF是在它们失败的时代产生的。 - GSerg
@GSerg:非常有趣,感谢分享链接。 - Heinzi
这种行为可能是由于WebServiceHost中的硬编码逻辑引起的。如果我使用DataContractJsonSerializernull字符串直接序列化,方法是通过以下方式执行:var ms = new MemoryStream(); new DataContractJsonSerializer(typeof(string)).WriteObject(ms, null); Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));,则结果是字符串null,而不是空字符串,这正是期望的结果。 - dbc
显示剩余3条评论
3个回答

6
你的json规范链接中包含了以下有趣的内容:

JSON是基于两种结构构建的:

  1. 名称/值对的集合。在不同的编程语言中,它被实现为对象、记录、结构、字典、散列表、关联数组等。

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

因此,我理解你的返回类型没有符合这个规范。
  1. public string GetNull() { return null; }

  2. public string GetSomeString() { return "SomeString"; }

为了符合规范,你需要将它们更改以匹配上述#1或#2之一。
  1. 使用struct:public struct structWithNull{public object resp;}默认值为null,因此public structWithNull GetNull() {return new structWithNull() ; }返回: null value returned by struct

  2. 使用大小为1的数组:public object[] GetNullArray() {return new object[1] ; }默认值再次为null;它返回: null value returned by one element array

在我看来,JSON基于封装数据,就像XML一样,始终需要一个父节点。因此,我猜没有其他解决方案可以使用struct/class (#1)或数组(#2)。 更新: 我发现这里有一个线索:rfc7159

请注意,之前的某些JSON规范将JSON文本限制为对象或数组。只生成对象或数组的实现在可互操作性方面是一致的,所有实现将接受它们作为符合JSON文本标准的文本。

如果我理解正确,你是对的,今天应该返回null,因为它是原语,但是不会,因为主要关注旧规定版本的仅对象和数组的行为。
最后,我认为只有Microsoft才能完全回答这个问题。

这是一个有趣的观点,但我认为你从JSON主页引用的内容并不意味着一个有效的JSON文本必须有一个对象或数组作为基本元素。如果我们查看页面链接的ECMA-404 PDF,我们会发现任何JSON值都是有效的JSON文本。引用一下(重点在于我):“JSON文本是由Unicode代码点形成的标记序列,符合JSON value语法。[...] JSON value可以是对象、数组、数字、字符串、truefalsenull**。”因此,null"""abc"将是有效的JSON文本,但``(空)则不是。 - Heinzi

0
在我看来,WCF 或其他方式都是数据传输契约,所有的数据都基于字符串。区别只在于如何约定字符串格式。
这种方法只返回一个字符串,无论格式如何,只有客户端可以获取数据,因此不需要使用 json 格式。
如果只返回字符串"null"表示null,如果我想返回字符串"null"而不是null,那就会混淆不清。当然,您可以使用转义字符解决它。也许他们认为什么都没有更好。
如果客户端使用 JSON 格式数据,只需返回字符串"null",然后客户端反序列化即可获得null,一切都没问题。无论返回什么,都要考虑如何对数据格式进行契约。

是的,重要的是发送者和接收者知道消息的含义。 - Florian p.i.

-1
如果您想在 JSON 格式的 WCF 响应中返回实际的 null 值,您应该定义一个数据契约并在不初始化它的情况下返回它。
[DataContract] 
public class Employee 
{ 
[DataMember]
public string id { get; set; }
}

现在在您的操作契约中,像这样返回它

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

那么在你的json响应中,你将获得null值。

希望它有所帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接