CSharp · Console
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 Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
//https://stackoverflow.com/questions/51802068/how-to-escape-especial-characters-in-json?noredirect=1#comment90566353_51802068
//https://stackoverflow.com/questions/51845381/how-to-escape-embedded-json-after-unescape
public class VData
{
public object RNumber { get; set; }
public string BRNumber { get; set; }
}
public class Number
{
[JsonProperty("@paraID")]
public string paraID { get; set; }
[JsonProperty("@Value")]
public string Value { get; set; }
[JsonProperty("@label")]
public string label { get; set; }
}
public class Evaluation
{
public List<Number> number { get; set; }
}
public class JsonFile
{
public Evaluation evaluation { get; set; }
public DateTime DateTime = DateTime.UtcNow;
public string PossibleNull = null;
}
public class OnlineFields
{
public string CCode { get; set; }
public string MNumber { get; set; }
public string Product { get; set; }
[JsonConverter(typeof(EmbeddedLiteralConverter<JsonFile>))]
public JsonFile JsonFile { get; set; }
}
public class Response
{
public object Message { get; set; }
public bool Error { get; set; }
public VData VData { get; set; }
public OnlineFields onlineFields { get; set; }
public DateTime DateTime = DateTime.UtcNow;
public string PossibleNull = null;
}
public class EmbeddedLiteralConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
using (new PushValue<bool>(true, () => Disabled, (canWrite) => Disabled = canWrite))
{
using (var sw = new StringWriter(writer.Culture))
{
// Copy relevant settings
using (var nestedWriter = new JsonTextWriter(sw)
{
DateFormatHandling = writer.DateFormatHandling,
DateFormatString = writer.DateFormatString,
DateTimeZoneHandling = writer.DateTimeZoneHandling,
StringEscapeHandling = writer.StringEscapeHandling,
FloatFormatHandling = writer.FloatFormatHandling,
Culture = writer.Culture,
// Remove if you don't want the escaped \r\n characters in the embedded JSON literal:
Formatting = writer.Formatting,
})
{
serializer.Serialize(nestedWriter, value);
}
writer.WriteValue(sw.ToString());
}
}
}
[ThreadStatic]
static bool disabled;
// Disables the converter in a thread-safe manner.
bool Disabled { get { return disabled; } set { disabled = value; } }
public override bool CanWrite { get { return !Disabled; } }
public override bool CanRead { get { return !Disabled; } }
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;
}
}
struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
#region IDisposable Members
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
#endregion
}
class TestClass
{
public static void Test()
{
var testJson = GetJson();
var settings = new JsonSerializerSettings
{
Converters = { new EmbeddedLiteralConverter<JsonFile>() },
DateFormatString = "yyyy-MM-dd",
NullValueHandling = NullValueHandling.Ignore,
};
var response = JsonConvert.DeserializeObject<Response>(testJson, settings);
var json2 = JsonConvert.SerializeObject(response, Formatting.Indented, settings);
Console.WriteLine(json2);
}
static string GetJson()
{
var json = @"{
""Message"":null,
""Error"":false,
""VData"":{
""RNumber"":null,
""BRNumber"":""Session1""
},
""onlineFields"":{
""CCode"":""Web"",
""MNumber"":""15478655"",
""Product"":""100"",
""JsonFile"":"" {
\""evaluation\"":{
\""number\"":[
{
\""@paraID\"":\""1000\"",
\""@Value\"":\""\"",
\""@label\"":\""We are america\""
},
{
\""@paraID\"":\""2000\"",
\""@Value\"":\""100\"",
\""@label\"":\""We are japan\""
},
{
\""@paraID\"":\""3000\"",
\""@Value\"":\""1000\"",
\""@label\"":\""We are UK\""
},
{
\""@paraID\"":\""4000\"",
\""@Value\"":\""\"",
\""@label\"":\""We are China\""
}
]
}
} ""
}
}";
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;
}
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
IsTrue(value, "failed");
}
public static void IsTrue(bool value, string message)
{
if (value == false)
throw new AssertionFailedException(message ?? "failed");
}
}