16

According to the JSON spec, the correct way to represent a null value is the literal null.

If that is the case, why does WCF return an empty response instead of null? Is this a bug or is this behaviour documented somewhere?

Complete repro example:

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();
    }
}

Expected result:

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

Actual result:

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

$
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • Because a null value can be represented in many different ways. See this post for more: http://stackoverflow.com/questions/21120999/representing-null-in-json – tom redfern Oct 03 '16 at 14:35
  • @TomRedfern: The accepted answer of that post also claims that `null` is the way null should be represented according to the JSON spec. My question is *why* WCF deviates from the spec. – Heinzi Oct 07 '16 at 14:08
  • In the light of the [recent answer](http://stackoverflow.com/a/39933043/11683), I wonder if your service actually responds with `Content-Type: application/json`? – GSerg Oct 08 '16 at 14:04
  • @GSerg: Good question, I just checked: It responds with `Content-Type: application/json; charset=utf-8` for GetSomeString and no Content-Type header for GetNull. As I commented below the answer, I believe that the quote from the JSON home page only summarizes the data structures which are available in addition to the primitive values rather than restricting the JSON "base element" to one of the two. – Heinzi Oct 08 '16 at 18:11
  • 1
    Related discussion: http://stackoverflow.com/q/18419428/11683. I believe it is particularly relevant, in addition to the accepted answer, that the primitives listed in the question [used to fail validation](http://stackoverflow.com/questions/18419428/what-is-the-minimum-valid-json#comment27059099_18419428) and now [they pass](http://jsonlint.com/), and WCF is from the era where they failed. – GSerg Oct 08 '16 at 18:57
  • @GSerg: Very interesting, thanks for the link. – Heinzi Oct 08 '16 at 19:16
  • Are you trying to return no JSON payload at all e.g. a 204 No Content response? As Florian has said in his answer, returning just a null that is without a root and other structures is not valid for a JSON response. – Dijkgraaf Oct 09 '16 at 21:08
  • This behavior may be due to hardcoded logic in `WebServiceHost`. If I serialize a `null` string with `DataContractJsonSerializer` directly by doing `var ms = new MemoryStream(); new DataContractJsonSerializer(typeof(string)).WriteObject(ms, null); Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));`, then the result is the string `null` as desired, and not the empty string. – dbc Oct 10 '16 at 02:47

3 Answers3

6

Your link to json specification includes these interesting lines:

JSON is built on two structures:

  1. A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.

  2. An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

So, in my understanding, your return types aren't conforming to the specification.

  • Neither public string GetNull() { return null; }

  • nor public string GetSomeString() { return "SomeString"; }

To fullfill the specifications you would have to change them to match either #1 or #2.

  1. A struct is used. public struct structWithNull{public object resp;} The default value is null, so public structWithNull GetNull() {return new structWithNull() ; } returns: null value returned by struct

  2. An array of size one is used. public object[] GetNullArray() {return new object[1] ; }. The default value is again null; it returns: null value returned by one element array

It seems to me that JSON is based of encapsulating data, like XML, where a parent node is always needed. So I guess that there is no other solution to this as to use a struct/class(#1) or an array(#2).

Update:

I found a clue here: rfc7159

Note that certain previous specifications of JSON constrained a JSON text to be an object or an array. Implementations that generate only objects or arrays where a JSON text is called for will be interoperable in the sense that all implementations will accept these as conforming JSON texts.

If I understand this correctly, your are right and null should be returned today as it is a primitive, but won't because the main focus might be on the old specified behavior of the only object and array based versions.

Finally I believe only Microsoft can answer this question completely.

Dijkgraaf
  • 11,049
  • 17
  • 42
  • 54
Florian p.i.
  • 622
  • 3
  • 7
  • This is an interesting point, but I believe that your quote from the JSON homepage does *not* imply that a valid JSON text must have an object or array as the base element. If we look at the ECMA-404 PDF linked from the page, we see that *any* JSON value is a valid JSON text. To quote (emphasis mine): *A JSON text is a sequence of tokens formed from Unicode code points that conforms to the JSON **value** grammar. [...] A JSON value can be an object, array, number, string, `true`, `false`, or **`null`**.* Thus, `null`, `""` and `"abc"` would be valid JSON texts, but `` (empty) would not. – Heinzi Oct 08 '16 at 18:01
0

In my opinion WCF or other ways are data transfer contract, and all data base on string. Difference just how you contract the string form.
This method just return a string, no matter how's the format only the client can get the data, so it doesn't need to be json format.
If just return string "null" represent null what if i want to return string "null" instead of null. It'll be confused. Of course you can use ESC characters solve it. Maybe they think nothing is better.
If client use json format data, you just return a string "null", then client deserialize it get a null, everything is ok. Anyway it's doesn't matter what return, but how to contract data format.

Bucketcode
  • 461
  • 2
  • 13
-1

If you want actual null values to be returned in your wcf response in json format you should define a datacontract and return it without initializing it

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

Now in your operation contract return it like this

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

Then you will null values in your json response.

Hope it helps

Hamza Ahmed
  • 1,571
  • 4
  • 18
  • 35