10

Given the following snippet:

using System;
using Newtonsoft.Json;

namespace JsonTestje
{
    class Other
    {
        public string Message2 { get; set; }
    }

    class Demo
    {
        public string Message { get; set; }
        public Other Other { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var demo = new Demo
            {
                Message = "Hello, World!",
                Other = new Other
                {
                    Message2 = "Here be dragons!"
                }
            };

            var settings = new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Auto,
                Formatting = Formatting.Indented
            };
            var serialized = JsonConvert.SerializeObject(demo, settings);
            Console.WriteLine(serialized);
        }
    }
}

The output is this:

{
  "Message": "Hello, World!",
  "Other": {
    "Message2": "Here be dragons!"
  }
}

Now if I change TypeNameHandling to TypeNameHandling.All, the output becomes this:

{
  "$type": "JsonTestje.Demo, JsonTestje",
  "Message": "Hello, World!",
  "Other": {
    "$type": "JsonTestje.Other, JsonTestje",
    "Message2": "Here be dragons!"
  }
}

But what I want is this:

{
  "$type": "JsonTestje.Demo, JsonTestje",
  "Message": "Hello, World!",
  "Other": {
    "Message2": "Here be dragons!"
  }
}

The reason is that I want to be able to serialize a bunch of objects and deserialize them later, without knowing the type that they deserialize to, but I also don't want to pollute the content with these $type properties all over the place where they're not needed.

In other words, I want TypeNameHandling.Auto except for the root object. How do I do this?

Dave Van den Eynde
  • 17,020
  • 7
  • 59
  • 90

1 Answers1

13

Well I figured it out by examining the source.

There's an overload that allows you to specify the 'root type' that you're passing. If the serializer finds that the type you passed is not the same (by being a descendant) it will write out the type name. The key is to specify System.Object as your root type, like this:

var serialized = JsonConvert.SerializeObject(demo, typeof(object), settings);
Dave Van den Eynde
  • 17,020
  • 7
  • 59
  • 90
  • In this last snippet, how is `settings` set? With `TypeNameHandling.Auto` or `TypeNameHandling.All`? – alelom Apr 07 '22 at 15:29
  • 1
    Judging from memory, I guess it's irrelevant as it applies to the rest of the object. This just removes that $type from the root. – Dave Van den Eynde Apr 08 '22 at 04:01
  • another simpler less hacky solution is to override the typeNameHandling on property level see https://stackoverflow.com/a/72493679/1361096 – Manuel Amstutz Jun 03 '22 at 18:20