https://stackoverflow.com/questions/56136560/json-net-c-sharp-deserialize-json-string-and-children-string

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Reflection;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;	

using NUnit.Framework; // Throws NUnit.Framework.AssertionException

//https://stackoverflow.com/questions/56136560/json-net-c-sharp-deserialize-json-string-and-children-string

	public class ItemAttribute
	{
		public string AttibuteName { get; set; }
		public string AttributeValue { get; set; }
	}

	public class SalesLine
	{
		public string SONumber { get; set; }
		public int LineNum { get; set; }
		public string ItemId { get; set; }
		public List<ItemAttribute> ItemAttributes { get; set; }
	}

	public class Value
	{
		public string documentType { get; set; }
		public string SONumber { get; set; }
		
		[JsonConverter(typeof(EmbeddedLiteralConverter<List<SalesLine>>))]
		public List<SalesLine> SalesLines { get; set; }
	}

	public class RootObject
	{
		public List<Value> value { get; set; }
	}

	public class EmbeddedLiteralConverter<T> : JsonConverter
	{
		public override bool CanConvert(Type objectType)
		{
			return typeof(T).IsAssignableFrom(objectType);
		}

		public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
		{
			if (reader.TokenType == JsonToken.Null)
				return null;
			var contract = serializer.ContractResolver.ResolveContract(objectType);
			if (contract is JsonPrimitiveContract)
				throw new JsonSerializationException("Invalid type: " + objectType);
			if (existingValue == null)
				existingValue = contract.DefaultCreator();
			if (reader.TokenType == JsonToken.String)
			{
				var json = (string)JToken.Load(reader);
				using (var subReader = new JsonTextReader(new StringReader(json)))
				{
					// By populating a pre-allocated instance we avoid an infinite recursion in EmbeddedLiteralConverter<T>.ReadJson()
					// Re-use the existing serializer to preserve settings.
					serializer.Populate(subReader, existingValue);
				}
			}
			else
			{
				serializer.Populate(reader, existingValue);
			}
			return existingValue;
		}

		public override bool CanWrite { get { return false; } }

		public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
		{
			throw new NotImplementedException();
		}
	}
	
    class TestClass
    {
        public static void Test()
        {
			TestConverter();
			ShowUnescapedJson();
		}	

		static void TestConverter()
		{
			var jsonString = GetJson();
			
			var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
			
			var json2 = JsonConvert.SerializeObject(root, Formatting.Indented);
			
			Console.WriteLine("\nDeserialized and re-serialized {0}", root);
			Console.WriteLine(json2);
		}
		
		public static void ShowUnescapedJson()
        {			
			Console.WriteLine("\nUnescaped JSON: ");

			var jsonString = GetJson();
			
			var json = JToken.Parse(jsonString);
			
			foreach(var token in json.SelectTokens("value[*].SalesLines").ToList())
			{
				token.Replace(JToken.Parse((string)token));
			}

			Console.WriteLine(json);
		}	

		
		static string GetJson()
		{
			var json = @"
{
   ""value"":[
      {
         ""documentType"":""Quote"",
         ""SONumber"":""S-QUO1001"",
         ""SalesLines"":""[{\""SONumber\"":\""S-QUO1001\"",\""LineNum\"":10000,\""ItemId\"":\""1936-S\"",\""ItemAttributes\"":[{\""AttibuteName\"":\""COLOR\"",\""AttributeValue\"":\""YELLOW\""},{\""AttibuteName\"":\""DEPTH\"",\""AttributeValue\"":\""100\""},{\""AttibuteName\"":\""WIDTH\"",\""AttributeValue\"":\""120\""},{\""AttibuteName\"":\""HEIGHT\"",\""AttributeValue\"":\""115\""},{\""AttibuteName\"":\""MATERIAL DESCRIPTION\"",\""AttributeValue\"":\""COTTON, WOOD LEGS\""},{\""AttibuteName\"":\""MODEL YEAR\"",\""AttributeValue\"":\""1940\""}]}]""
      }
   ]
}

";
			return json;
		}
	}

	public class Program
	{
		public static void Main()
		{
			Console.WriteLine("Environment version: " + Environment.Version);
			Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
			Console.WriteLine();

			try
			{
				TestClass.Test();
			}
			catch (Exception ex)
			{
				Console.WriteLine("Failed with unhandled exception: ");
				Console.WriteLine(ex);
				throw;
			}
		}
	}
;