5

I want to Deserialize JSON into Object but I don't want to Deserialize nested JSON, nested of nested JSON should convert into JSON list (Please check "My expected output" for clear idea) ...

// Suppose I have below JSON data, Here I have nested JSON for "Address" entity

String jsonEmployees =
"{"Employees":
[{"EmpId":1, "EmpName":"ABC", "Address":[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]},
{"EmpId":2, "EmpName":"XYZ", "Address":[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]}]
}"

public class Employee
{
    public int EmpId { get; set; }
    public string EmpName { get; set; }
    // **Note** : I'm not using List<Address> data type for Address, instead of I want list of address in JSON string
    public string Address { get; set; }
}

public class RootObject
{
    public List<Employee> Employees { get; set; }
}

var Employees = JsonConvert.DeserializeObject<RootObject>(jsonEmployees);

// My expected output

Employees[0].EmpId = 1;
Employees[0].EmpName = "ABC";
Employees[0].Address = "[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]";

Employees[1].EmpId = 2;
Employees[1].EmpName = "XYZ";
Employees[1].Address = "[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]";

Please suggest me the best way to solve this issue ...

Shri
  • 351
  • 3
  • 16

3 Answers3

9

Your question is, How can I serialize and deserialize a type with a string member that contains "raw" JSON, without escaping the JSON in the process?

This can be done via a custom JsonConverter that reads and writes raw JSON using JsonWriter.WriteRawValue() and JRaw.Create():

public class RawConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var raw = JRaw.Create(reader);
        return raw.ToString();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var s = (string)value;
        writer.WriteRawValue(s);
    }
}

Then apply it to your type as follows:

public class Employee
{
    public int EmpId { get; set; }
    public string EmpName { get; set; }
    // **Note** : I'm not using List<Address> data type for Address, instead of I want list of address in JSON string
    [JsonConverter(typeof(RawConverter))]
    public string Address { get; set; }
}

public class RootObject
{
    public List<Employee> Employees { get; set; }
}

Sample fiddle.

Note that the raw JSON string must represent valid JSON. If it does not, then the JSON created will be unreadable. If you want to guarantee that the JSON literal is valid, you can keep the JSON in a parsed state internally:

public class Employee
{
    public int EmpId { get; set; }
    public string EmpName { get; set; }

    [JsonProperty("Address")]
    JToken AddressToken { get; set; }

    [JsonIgnore]
    public string Address
    {
        get
        {
            if (AddressToken == null)
                return null;
            return AddressToken.ToString(Formatting.Indented); // Or Formatting.None if you prefer
        }
        set
        {
            if (value == null)
                AddressToken = null;
            else
                // Throw an exception if value is not valid JSON.
                AddressToken = JToken.Parse(value);
        }
    }
}

A converter is not needed for this implementation.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • Thanks **@dbc** ... It **resolved** my problem both solutions working perfectly ... Thanks again for your valuable solution ... – Shri Nov 11 '16 at 10:12
1

I think you will have to rebuild your list of Employees :

        RootObject Employees = JsonConvert.DeserializeObject<RootObject>(jsonEmployees);

        List<Employee> EmployeesNew = new List<Employee>();

        foreach (var item in Employees.Employees)
        {
            string StringAddress = JsonConvert.SerializeObject(item.Address, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
            EmployeesNew.Add(new Employee { EmpId = item.EmpId, EmpName = item.EmpName, AddressString = StringAddress });

        }

Your class:

    public class Employee
    {
        public int EmpId { get; set; }
        public string EmpName { get; set; }
        // **Note** : I'm not using List<Address> data type for Address, instead of I want list of address in JSON string
        public List<AddressItems> Address { get; set; }
        public string AddressString { get; set; }
    }

    public class RootObject
    {
        public List<Employee> Employees { get; set; }
    }

    public class AddressItems
    {
        public int AddressId { get; set; }
        public string Address { get; set; }
    }
Yanga
  • 2,885
  • 1
  • 29
  • 32
  • Yanga - I think this will work for me but it's tittle bit lengthy process ... My problem is resoled by **dbc** ... Thanks for you valuable time ... – Shri Nov 11 '16 at 10:03
0

In JSON curly brackets {} are the notation for an object, and square brackets [] are for arrays.

As long as your array is encapsulated in the curly brackets like that, you'll have to use another containing object. If you can get rid of the {"Employees": prefix and } suffix, you should be able to convert the JSON to a list of employees directly.

EDIT: I'm sorry, I didn't understand the question.

To do what you want is either really simple, or really difficult, depending on whether you can control the JSON.

If you can control the JSON, all you need to do is add single quotes around the address value so it'll look like this:

[{"EmpId":1, "EmpName":"ABC", "Address":'[{"AddressId":1, "Address":"Something"},{"AddressId":2, "Address":"Anything"}]'},

And that's it! now the serializer will convert it to string.

If you can't than you have to deserialize the JSON by yourself, token by token. Or you can do a workaround, create a corresponding address class, and let the serializer convert to it. Then add a calculated property and use the serializer to deserialize the addresses back to JSON.
(Ugly, I know, but it'll be much faster to implement).

CKII
  • 1,439
  • 14
  • 26
  • I'm able to convert above JSON into list of Employees .. But my question is how I can Deserialize (Convert) above JSON to Employee object so that my Address entity data will be in JSON format instead of List
    . Please check my expected output ... Correct me if I'm expecting something which not possible or tell if your solution is for the same ...
    – Shri Nov 10 '16 at 14:23