1

All, when executing the following code we are running into the following exception (in bold), we are trying to add the rootnode "test" to the end json result. we want to achieve this without anonymous objects or wrapper classes.

"Cannot write a JSON property within an array or as the first JSON token. Current token type is 'None'.

 internal static class Program
    {
        public static void Main(string[] args)
        {
            customer cust = new customer();
            cust.firstname = "first";
            cust.lastname = "last";

            Console.WriteLine(AddRootToJson("test", cust));
        }

        public static string AddRootToJson(string root, object obj)
        {
            var msSt = new MemoryStream {Position = 0};
            using var utf8JsonWriter = new Utf8JsonWriter(msSt);
            utf8JsonWriter.WriteStartObject(root);
            JsonSerializer.Serialize(utf8JsonWriter, obj);
            utf8JsonWriter.WriteEndObject();
            utf8JsonWriter.Flush();
            using var reader = new StreamReader(msSt);
            return reader.ReadToEnd();
        }
    }


    public class customer
    {
        public string firstname;
        public string lastname;
    }
3
  • What is "root element"? You want something like {"test": {"firstname": "", "lastname": ""}}? Commented Jul 10, 2020 at 13:53
  • Is there a reason to not add the property to the Customer class? Is it because you just need this property in the output, but no other place in the application? Commented Jul 10, 2020 at 14:03
  • I know you said "no wrappers", BUT you can create a generic wrapper. class JsonNeedsSingleRootWorkaround<T> { public string Uid { get; private set; } = Guid.NewGuid().ToString("N"); /* this is purposely a List<T> to deal with json serialization issues */ public List<T> Items { get; set; } } Commented Jul 10, 2020 at 18:51

2 Answers 2

5

First of all currently System.Text.Json does not support serializing fields, so you will need to change your class (see Support for public and non-public fields in docs):

public class customer
{
    public string firstname {get;set;}
    public string lastname {get;set;}
}

After that you can try next:

public static string AddRootToJson(string root, object obj)
{
    using var msSt = new MemoryStream();
    using var utf8JsonWriter = new Utf8JsonWriter(msSt);
    utf8JsonWriter.WriteStartObject();
    utf8JsonWriter.WritePropertyName(root);
    JsonSerializer.Serialize(utf8JsonWriter, obj);
    utf8JsonWriter.WriteEndObject();
    utf8JsonWriter.Flush();
    return Encoding.UTF8.GetString(msSt.ToArray());
}

Console.WriteLine(AddRootToJson("test", new customer {firstname = "first", lastname = "last"})); // prints {"test":{"firstname":"first","lastname":"last"}}
Sign up to request clarification or add additional context in comments.

1 Comment

If you are running on .NET Core, and performance is important, instead of using a MemoryStream and then calling .ToArray() on it, you can use ArrayBufferWriter<byte> instead and save that extra allocation. After Flush call Encoding.UTF8.GetString(ReadOnlySpan<Byte>) passing in the WrittenSpan property learn.microsoft.com/en-us/dotnet/api/…
0

If i have understood you correct you want to in the result something like this:

{"test",
    [
      {"first",
      "last"}
      ....
    ]
}

Just create for it another model:

public class FullModel
{
    public List<Customer> Customers {get;set;}
    public string Root {get;set;}
}

And change your Customer class:

public class Customer
{
    public string FirstName {get;set;}
    public string LastName {get;set;}
}

Now, step by step:

public static void Main(string[] args)
    {
        List<Customer> customers = new List<Customers>();
        customers.Add(new Customer{FirstName="first",LastName="last"});
        FullModel fullModel = new FullModel
        {
            Root = "test",
            Customers = customers
        };
         
        Console.WriteLine(AddRootToJson(cust));
    }

public static string AddRootToJson(object obj)
    {
        var msSt = new MemoryStream {Position = 0};
        using var utf8JsonWriter = new Utf8JsonWriter(msSt);
        JsonSerializer.Serialize(utf8JsonWriter, obj);
        utf8JsonWriter.WriteEndObject();
        utf8JsonWriter.Flush();
        using var reader = new StreamReader(msSt);
        return reader.ReadToEnd();
    }

You can change method in depend of your view. Hope it will help you. Good luck.

1 Comment

OP specifically wrote that "we want to achieve this without anonymous objects or wrapper classes."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.