How can I parse json to a C# object (Class)? - c#

I have JSON data that I need to parse from C# object.
this is JSON Example.
{
"types":
[
[
"tour_type",
[
["groups",1],
["individual",2]
]
]
]
}
Here are my C# classes that are meant to contain that data:
using System;
using Newtonsoft.Json;
namespace JsonDeserializationTest
{
[JsonProperty("types")]
public class Types
{
[JsonProperty]
public List<Type> Values {get;set;}
}
public class Type
{
[JsonProperty]
public string Key {get;set;}
[JsonProperty]
public List<Dictionary<string, int>> Values { get; set; }
}
}
It's not working now.
How can I fix it?

Use the JsonSerializer (System.Text.Json) object.
Code:
YourClass obj = JsonSerializer.Deserialize<YourClass>(jsonString);

Your json has a list of list of the object... but you are declaring only List of the object.
public class Types
{
[JsonProperty("types")]
public List<List<object>> Values { get; set; }
// ------ UPDATE: This can only be list of list of 'object' ------- \\
}
Also, you are using the JsonProperty on the class, which is not where that normally goes. You want to use that on the property of the class.
UPDATE:
You cannot use List<List<Type>> for the json you are getting, it can only be List<List<object>>. You have to use object because it can either be a string or a List<List<string>>. After you update your Types class, you can successfully deserialize the json above.
var obj = JsonConvert.DeserializeObject<Types>(json);
and based on your json definition, you can access tour_type by using the following code
types.Values.First()[0].ToString()
// output: tour_type
List<List<string>> data = JsonConvert.DeserializeObject<List<List<string>>>(types.Values.First()[1].ToString())
// data[0]
[0]: "groups"
[1]: "1"
// data[1]
[0]: "individual"
[1]: "2"
Since both of the items in the types are objects, you will either have to convert them to string or a list of list of strings or whatever object they actually are.

The JSON payload in the provided example is formatted quite strangely, especially since it contains seemingly unnecessary array nesting. A payload like this usually includes more nested objects (rather than a bunch of nested arrays). Additionally, it has a list of (string, int) pairs, which is semantically very similar to a Dictionary<string, int>, but the payload doesn't lend itself to that. It would be helpful to know where it is coming from (what context) to understand how it might change.
The example JSON brings up a few questions (that you may want to ask yourself):
Can the "types" array contain multiple entries (at its immediate nesting)?
Can the "tour_type" key name appear after the array of string, int pairs? Is it possible for an entry where no such name exists?
What other elements can exist in the arrays within "tour_type"?
Is it guaranteed that the most nested array will contain just a single (string, int) pair?
Similarly, it is hard to understand what the example C# class is trying to encapsulate. Is List<Dictionary<string, int>> necessary?
All that said, here's a solution using the built-in System.Text.Json library, that could work for you. You could write something similar using Newtonsoft.Json, if necessary. The solution assumes:
We can't change the JSON payload (and that the third party API response will always returns something that is structurally similar to the example)
We can only make minimal changes to the C# class object provided in the example
The solution creates and a JsonConverter<T> that uses the low-level Utf8JsonReader to manually parse and create the custom object. This is required since nested "[" are being used to delineate what should be objects rather than "{". The converter is then registered by annotating the class with the attribute. Now, simply call JsonSerializer.Deserialize, passing in the JSON payload.
public class Tours
{
[JsonPropertyName("types")]
public List<UserType> Types { get; set; }
}
// Annotate the type to register the converter to use
[JsonConverter(typeof(CustomUserTypeConverter))]
public class UserType
{
public string Key { get; set; }
public Dictionary<string, int> Values { get; set; }
}
// This will use the low-level reader to build up the UserType
public class CustomUserTypeConverter : JsonConverter<UserType>
{
// Extra structural validation was done for invalid/incomplete JSON
// which might be too strict or incorrect and hence might require adjustments.
public override UserType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var result = new UserType();
if (!reader.Read())
{
throw new JsonException("Incomplete JSON.");
}
if (reader.TokenType != JsonTokenType.EndArray)
{
result.Key = reader.GetString();
ReadAndValidate(ref reader, JsonTokenType.StartArray);
int depthSnapshot = reader.CurrentDepth;
var values = new Dictionary<string, int>();
do
{
reader.Read();
if (reader.TokenType != JsonTokenType.StartArray && reader.TokenType != JsonTokenType.EndArray)
{
throw new JsonException($"Invalid JSON payload. Expected Start or End Array. TokenType: {reader.TokenType}, Depth: {reader.CurrentDepth}.");
}
if (reader.CurrentDepth <= depthSnapshot)
{
break;
}
reader.Read();
if (reader.TokenType != JsonTokenType.EndArray)
{
string key = reader.GetString();
reader.Read();
int value = reader.GetInt32();
values.Add(key, value);
ReadAndValidate(ref reader, JsonTokenType.EndArray);
}
} while (true);
ReadAndValidate(ref reader, JsonTokenType.EndArray);
result.Values = values;
}
return result;
}
private void ReadAndValidate(ref Utf8JsonReader reader, JsonTokenType expectedTokenType)
{
bool readNext = reader.Read();
if (!readNext || reader.TokenType != expectedTokenType)
{
string message = readNext ?
$"Invalid JSON payload. TokenType: {reader.TokenType}, Depth: {reader.CurrentDepth}, Expected: {expectedTokenType}" :
$"Incomplete JSON. Expected: {expectedTokenType}";
throw new JsonException(message);
}
}
// Implement this method if you need to Serialize (i.e. write) the object
// back to JSON
public override void Write(Utf8JsonWriter writer, UserType value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
Here's how you would use the above converter to serialize the JSON string provided in the example, along with how to access the values.
public static Tours ParseJson(string json)
{
Tours tours = JsonSerializer.Deserialize<Tours>(json);
return tours;
}
public static void AccessValues(Tours tours)
{
foreach (UserType data in tours.Types)
{
string typeName = data.Key; // "tour_type"
foreach (KeyValuePair<string, int> pairs in data.Values)
{
string key = pairs.Key; // "groups" or "individual
int value = pairs.Value; // 1 or 2
}
}
}
For what it's worth, Visual Studio suggests the following C# class structure for the example JSON (which is similar to what #Jawad suggested):
public class Rootobject
{
public object[][] types { get; set; }
}
Hope that helps.

I couldn't figure out your JSON so I created an example with verified JSON.
Try this:
JSON:
{
"Items": [
{
"Name": "tour",
"Attributes": [
{
"Name": "groups",
"Value": 1
},
{
"Name": "individual",
"Value": 2
}
]
},
{
"Name": "demo",
"Attributes": [
{
"Name": "this is demo",
"Value": 3
},
{
"Name": "design pattern",
"Value": 99
}
]
}
]
}
Types foo = JsonSerializer.Deserialize<Types>(jsonString);
public class TypeAttribute
{
public string Name { get; set; }
public int Value { get; set; }
}
public class Type
{
private readonly ICollection<TypeAttribute> _attributes;
public Type()
{
_attributes = new Collection<TypeAttribute>();
}
public void AddAttributes(IEnumerable<TypeAttribute> attrs)
{
foreach(TypeAttribute ta in attrs)
{
_attributes.Add(ta);
}
}
public string Name { get; set; }
public IEnumerable<TypeAttribute> Attributes
{
get { return _attributes; }
set
{
foreach(TypeAttribute ta in value)
{
_attributes.Add(ta);
}
}
}
}
public class Types
{
ICollection<Type> _items;
public Types()
{
_items = new Collection<Type>();
}
public void AddItems(IEnumerable<Type> tps)
{
foreach (Type t in tps)
{
_items.Add(t);
}
}
public IEnumerable<Type> Items
{
get { return _items; }
set
{
foreach (Type t in value)
{
_items.Add(t);
}
}
}
}

Related

Convert a Json to Json object to Json array (NOT by using JsonReader)

This is the Json that I am reading from a (.)json file.
{
"steps": [
{
"stepType": "runFolderUpdate",
"stepData": {
"actionType": "update",
"folderData": {
"folderName": "New Folder 1",
"dirName": "C:/demo/demo.xml",
"machineAddress": "10.23.44.12"
}
}
},
{
"stepType": "runFolderCreate",
"stepData": {
"actionType": "create",
"actionData": {
"folderName": "New Folder 2",
"dirName": "C:/Demo",
"machineAddress": "10.23.211.2"
}
}
},
{ . . . },
{ . . . }
]
}
My requirement is to get an Array out of this Json so that I can have all the fields and can access it with help of "stepType" and further with the help of "actionType" value.
For stepType = "runFolderUpdate"
{
"stepType": "runFolderUpdate",
"stepData": {
"actionType": "update",
"folderData": {
"folderName": "New Folder 1",
"dirName": "C:/demo/demo.xml",
"machineAddress": "10.23.44.12"
}
}
}
For stepType = "runFolderCreate"
{
"stepType": "runFolderCreate",
"stepData": {
"actionType": "create",
"actionData": {
"folderName": "New Folder 2",
"dirName": "C:/Demo",
"machineAddress": "10.23.211.2"
}
}
}
So now that I have two blocks, one for create and one for update, I can go on and access values per requirement and I am not restricted to how the JSON keys are arranged.
I tried to do it using JsonReader from Newtonsoft library but the problem is it is only forward moving reader and I can not go back. Now since this is a JSON file we are talking about, so order of how the Keys are placed should not matter but with JsonReader I get my hands tied.
Lets say for example, I am if stepType is below stepData then I can not use a JsonReader to go back to stepData afetr I know what type of stepType I am talking about.
I am looking on an approach on how to convert this steps object Json to array and each blob will be act as a block of information which I can access (Just like we do in array, using index so I dont have to worry about the order of keys.
////////UPDATE////////
I am trying to do something like this....
JObject object = Read Json from file...
JArray array = object.get("steps");
Now that I have array, based on stepType I can work on...
is this even possible?
You can convert all this to C# classes fairly easily with a custom converter. Newtonsoft gives some really useful extensibility points. So, lets say you had the following class structure:
public class Root
{
public List<Step> Steps { get; set; }
}
// Here we are telling the serialiser to use the converter
[JsonConverter(typeof(StepConverter))]
public class Step
{
public string StepType { get; set; }
public IStepData StepData { get; set; }
}
public interface IStepData
{
string ActionType { get; set; }
}
public class RunFolderUpdate : IStepData
{
public string ActionType { get; set; }
//etc - you can fill in the rest here
}
public class RunFolderCreate : IStepData
{
public string ActionType { get; set; }
//etc - you can fill in the rest here
}
Now we can implement the converter like this:
public class StepConverter : JsonConverter<Step>
{
public override Step ReadJson(JsonReader reader, Type objectType,
[AllowNull] Step existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var step = JObject.ReadFrom(reader);
var stepType = step["stepType"].Value<string>();
switch(stepType)
{
case "runFolderUpdate":
return new Step
{
StepType = stepType,
StepData = step["stepData"].ToObject<RunFolderUpdate>()
};
case "runFolderCreate":
return new Step
{
StepType = stepType,
StepData = step["stepData"].ToObject<RunFolderCreate>()
};
}
throw new Exception("Errr, unknown step type!");
}
public override void WriteJson(JsonWriter writer, [AllowNull] Step value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
And finally you can deserialise like this:
var result = JsonConvert.DeserializeObject<Root>(json);
You can use JObject, JToken and JArray for your for work.
Say for your Json, your Json starts with an object...it has a "[" followed which is representation of an Array i.e. JArray...so you can do something like this...
So once you get "steps" as object like this...
JObject obj= null;
using (StreamReader file = File.OpenText(filePath))
using (JsonTextReader reader = new JsonTextReader(file))
{
obj = (JObject)JToken.ReadFrom(reader);
}
JToken token = obj.GetValue("steps");
JArray array = (JArray) token;
Now that you have an array which looks like this...since it has read "steps" already
[
{ .... },
{ .... }
]
Every curly brace is you array index (here Json object) you can reach using for loop...
for (int i = 0; i < array.length(); i++) {
//Now here get the next token which is an object again so you can
//parse through it and perform your action as needed for create or update
}
This is a same as java.
Dont worry about order of keys, JObject gives you freedom and you DO NOT NEED a model for this...Model is sure cleaner way to do, but it is tightly coupled, so if your Json changes, its of no use.
Please mark as answer if you feel this is correct.

Adding a root element to json

I am generating a json string using NewtosoftJson using a table to format the the json. This is a simple key value pairs list and looks like:
public class items
{
private string key = String.Empty;
private string value = String.Empty;
public string Key
{
get
{
return key;
}
set
{
if (value != key)
{
key = value;
}
}
}
public string Value
{
get
{
return value;
}
set
{
if (value != this.value)
{
this.value = value;
}
}
}
}
When a list is populated and then serialised I get this JSON:
"Items": [
{
"Key":"FirstValue",
"Value":"One"
},
{
"Key":"SecondValue",
"Value":"Two"
},
{
"Key":"ThirdValue",
"Value":"Three"
}
]
What I need to get is:
"customData": {
"items": [
{
"Key":"FirstValue",
"Value":"One"
},
{
"Key":"SecondValue",
"Value":"Two"
},
{
"Key":"ThirdValue",
"Value":"Three"
}
]
}
I have tried creating a second class CustomData but can't see how to get the original JSON into the second class! Could you advice me on the correct way to construct the second class and method used to populate it please.
You can create an anonymous object and serialize that:
var objContainingItems = ... // your usual code
var customDataObj = new { customData = objContainingItems };
string json = JsonConvert.SerializeObject(customDataObj);
This is the most convenient solution if all you are interested in is serializing.
If you also want to be able to deserialize it, then you will need to use a class as specified in the answer by #William Moore.
Create a class customData and create a reference to the class items inside it. Then serialise your customData class using Newtonsoft.Json rather than your items class. So you will have:
public class CustomData
{
public items[] items; // I would rename the class items to item
}
Then you have an object of type customData, called customData which you pass into Newtonsoft.
You could then use the following to serialise/deserialise your data:
CustomData input = new CustomData();
input.items = []; // Whatever you have at the moment?
string json = JsonConvert.SerializeObject(account) //optionally set Formatting.Indented
CustomData deserialised = JsonConvert.DeserializeObject<CustomData>(json);

Dotnet core -> Newtonsoft DeserializeObject<T> with Dynamic Child [duplicate]

Given following json result:
The default json result has a known set of fields:
{
"id": "7908",
"name": "product name"
}
But can be extended with additional fields (in this example _unknown_field_name_1 and _unknown_field_name_2) of which the names are not known when requesting the result.
{
"id": "7908",
"name": "product name",
"_unknown_field_name_1": "some value",
"_unknown_field_name_2": "some value"
}
I would like the json result to be serialized and deserialized to and from a class with properties for the known fields and map the unknown fields (for which there are no properties) to a property (or multiple properties) like a dictionary so they can be accessed and modified.
public class Product
{
public string id { get; set; }
public string name { get; set; }
public Dictionary<string, string> fields { get; set; }
}
I think I need a way to plug into a json serializer and do the mapping for the missing members myself (both for serialize and deserialize).
I have been looking at various possibilities:
json.net and custom contract resolvers (can't figure out how to do it)
datacontract serializer (can only override onserialized, onserializing)
serialize to dynamic and do custom mapping (this might work, but seems a lot of work)
let product inheriting from DynamicObject (serializers work with reflection and do not invoke the trygetmember and trysetmember methods)
I'm using restsharp, but any serializer can be plugged in.
Oh, and I cannot change the json result, and this or this didn't help me either.
Update:
This looks more like it: http://geekswithblogs.net/DavidHoerster/archive/2011/07/26/json.net-custom-convertersndasha-quick-tour.aspx
An even easier option to tackling this problem would be to use the JsonExtensionDataAttribute from JSON .NET
public class MyClass
{
// known field
public decimal TaxRate { get; set; }
// extra fields
[JsonExtensionData]
private IDictionary<string, JToken> _extraStuff;
}
There's a sample of this on the project blog here
UPDATE Please note this requires JSON .NET v5 release 5 and above
See https://gist.github.com/LodewijkSioen/5101814
What you were looking for was a custom JsonConverter
This is a way you could solve it, although I don't like it that much. I solved it using Newton/JSON.Net. I suppose you could use the JsonConverter for deserialization aswell.
private const string Json = "{\"id\":7908,\"name\":\"product name\",\"_unknown_field_name_1\":\"some value\",\"_unknown_field_name_2\":\"some value\"}";
[TestMethod]
public void TestDeserializeUnknownMembers()
{
var #object = JObject.Parse(Json);
var serializer = new Newtonsoft.Json.JsonSerializer();
serializer.MissingMemberHandling = Newtonsoft.Json.MissingMemberHandling.Error;
serializer.Error += (sender, eventArgs) =>
{
var contract = eventArgs.CurrentObject as Contract ?? new Contract();
contract.UnknownValues.Add(eventArgs.ErrorContext.Member.ToString(), #object[eventArgs.ErrorContext.Member.ToString()].Value<string>());
eventArgs.ErrorContext.Handled = true;
};
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(Json)))
using (StreamReader streamReader = new StreamReader(memoryStream))
using (JsonReader jsonReader = new JsonTextReader(streamReader))
{
var result = serializer.Deserialize<Contract>(jsonReader);
Assert.IsTrue(result.UnknownValues.ContainsKey("_unknown_field_name_1"));
Assert.IsTrue(result.UnknownValues.ContainsKey("_unknown_field_name_2"));
}
}
[TestMethod]
public void TestSerializeUnknownMembers()
{
var deserializedObject = new Contract
{
id = 7908,
name = "product name",
UnknownValues = new Dictionary<string, string>
{
{"_unknown_field_name_1", "some value"},
{"_unknown_field_name_2", "some value"}
}
};
var json = JsonConvert.SerializeObject(deserializedObject, new DictionaryConverter());
Console.WriteLine(Json);
Console.WriteLine(json);
Assert.AreEqual(Json, json);
}
}
class DictionaryConverter : JsonConverter
{
public DictionaryConverter()
{
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Contract);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var contract = value as Contract;
var json = JsonConvert.SerializeObject(value);
var dictArray = String.Join(",", contract.UnknownValues.Select(pair => "\"" + pair.Key + "\":\"" + pair.Value + "\""));
json = json.Substring(0, json.Length - 1) + "," + dictArray + "}";
writer.WriteRaw(json);
}
}
class Contract
{
public Contract()
{
UnknownValues = new Dictionary<string, string>();
}
public int id { get; set; }
public string name { get; set; }
[JsonIgnore]
public Dictionary<string, string> UnknownValues { get; set; }
}
}
I thought I'd throw my hat in the ring since I had a similar problem recently. Here's an example of the JSON I wanted to deserialize:
{
"agencyId": "agency1",
"overrides": {
"assumption.discount.rates": "value: 0.07",
".plan": {
"plan1": {
"assumption.payroll.growth": "value: 0.03",
"provision.eeContrib.rate": "value: 0.35"
},
"plan2": {
".classAndTier": {
"misc:tier1": {
"provision.eeContrib.rate": "value: 0.4"
},
"misc:tier2": {
"provision.eeContrib.rate": "value: 0.375"
}
}
}
}
}
}
This is for a system where overrides apply at different levels and are inherited down the tree. In any case, the data model I wanted was something that would allow me to have a property bag with these special inheritance rules also supplied.
What I ended up with was the following:
public class TestDataModel
{
public string AgencyId;
public int Years;
public PropertyBagModel Overrides;
}
public class ParticipantFilterModel
{
public string[] ClassAndTier;
public string[] BargainingUnit;
public string[] Department;
}
public class PropertyBagModel
{
[JsonExtensionData]
private readonly Dictionary<string, JToken> _extensionData = new Dictionary<string, JToken>();
[JsonIgnore]
public readonly Dictionary<string, string> Values = new Dictionary<string, string>();
[JsonProperty(".plan", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, PropertyBagModel> ByPlan;
[JsonProperty(".classAndTier", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, PropertyBagModel> ByClassAndTier;
[JsonProperty(".bargainingUnit", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<string, PropertyBagModel> ByBarginingUnit;
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
foreach (var kvp in Values)
_extensionData.Add(kvp.Key, kvp.Value);
}
[OnSerialized]
private void OnSerialized(StreamingContext context)
{
_extensionData.Clear();
}
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
Values.Clear();
foreach (var kvp in _extensionData.Where(x => x.Value.Type == JTokenType.String))
Values.Add(kvp.Key, kvp.Value.Value<string>());
_extensionData.Clear();
}
}
The basic idea is this:
The PropertyBagModel on deserialization by JSON.NET has the ByPlan, ByClassAndTier, etc. fields populated and also has the private _extensionData field populated.
Then JSON.NET calls the private OnDeserialized() method and that will move the data from _extensionData to Values as appropriate (or drop it on the floor otherwise - presumably you could log this if it was something you wanted to know). We then remove the extra gunk from _extensionData so it doesn't consume memory.
On serialization, the OnSerializing method gets calls where we move stuff into _extensionData so it gets saved.
When serialization has finished, OnSerialized gets called and we remove the extra stuff from _extensionData.
We could further delete and recreate the _extensionData Dictionary when needed but I didn't see a real value in this as I'm not using tons of these objects. To do this we'd just create on OnSerializing and delete on OnSerialized. On OnDeserializing, instead of clearing, we could free it.
I was looking into a similar issue and found this post.
Here is a way to do it using reflection.
To make it more generic, one should check the type of the property instead of simply using ToString() in propertyInfo.SetValue, unless OFC all the actual properties are strings.
Also, lowercase property names is not standard in C# but given that GetProperty is case sensitive there are few other options.
public class Product
{
private Type _type;
public Product()
{
fields = new Dictionary<string, object>();
_type = GetType();
}
public string id { get; set; }
public string name { get; set; }
public Dictionary<string, object> fields { get; set; }
public void SetProperty(string key, object value)
{
var propertyInfo = _type.GetProperty(key);
if (null == propertyInfo)
{
fields.Add(key,value);
return;
}
propertyInfo.SetValue(this, value.ToString());
}
}
...
private const string JsonTest = "{\"id\":7908,\"name\":\"product name\",\"_unknown_field_name_1\":\"some value\",\"_unknown_field_name_2\":\"some value\"}";
var product = new Product();
var data = JObject.Parse(JsonTest);
foreach (var item in data)
{
product.SetProperty(item.Key, item.Value);
}

Serialize and deserialize part of JSON object as string with WCF

I have a WCF REST service which has a resource which contains several typed fields, and then a field which can be an array of objects. I want the field on our service to serialize this field as if it were a string. Example:
[DataContract]
public class User
{
[DataMember]
public long ID;
[DataMember]
public string Logon;
[DataMember]
public string Features;
}
When users of our API POST a new User object, I'd like them to be able to do use something like this as the body:
{
"ID" : 123434,
"Logon" : "MyLogon",
"Features" : [
{ "type": "bigFeature", "size": 234, "display":true },
{ "type": "smFeature", "windowCount": 234, "enableTallness": true}
]
}
instead of
{
"ID" : 123434,
"Logon" : "MyLogon",
"Features" : "[
{ \"type\": \"bigFeature\", \"size\": 234, \"display\":true },
{ \"type\": \"smFeature\", \"windowCount\": 234, \"enableTallness\": true}
]"
}
On the service side, I'm going to be saving the "Features" array as JSON text blog in the database, and when I return the Object on GET calls, I'd like it to round trip properly.
If you were willing to switch to Json.NET, you could serialize your Features string as a private JToken proxy property:
[DataContract]
public class User
{
[DataMember]
public long ID;
[DataMember]
public string Logon;
string _features = null;
[IgnoreDataMember]
public string Features
{
get
{
return _features;
}
set
{
if (value == null)
_features = null;
else
{
JToken.Parse(value); // Throws an exception on invalid JSON.
_features = value;
}
}
}
[DataMember(Name="Features")]
JToken FeaturesJson
{
get
{
if (Features == null)
return null;
return JToken.Parse(Features);
}
set
{
if (value == null)
Features = null;
else
Features = value.ToString(Formatting.Indented); // Or Formatting.None, if you prefer.
}
}
}
Note that, in order to serialize the Features string without escaping, it must be valid JSON, otherwise your outer JSON will be corrupt. I enforce this in the setter. You could use JArray instead of JToken to enforce the requirement that the string represent a JSON array, if you prefer.
Note that the string formatting isn't preserved during serialization.

How to avoid fields when deserialize the JSON response directly into a strongly typed object?

I have a json response displayed as below. I am using datacontractserializer to serialize.
If I need only "text" and "created time" from this Json response...how should be my DataContract looks like?
Do I need to have all these six properties in my data contract ? and use "IgnoreDataMember" as attribute?
Also, do I need to give same name for my properties in datacontract (Ex : screenName, text as property name ?)
"abcDetails":[
{
"screenName":"my name",
"text":"tweet desc",
"createdTime":1423494304000,
"entities":{ },
"name":"abc",
"id":"123"
}]
To answer your questions:
You can omit properties that you do not need and DataContractJsonSerializer will skip over them.
You class's property names can differ from the JSON property names as long as you set the DataMemberAttribute.Name value to be the same as the name appearing in the JSON.
Your JSON is invalid, it is missing outer braces. I assume that's just a copy/paste error in your question.
Thus your classes could look like:
[DataContract]
public class Detail
{
[DataMember(Name="text")]
public string Text { get; set; }
[DataMember(Name="createdTime")]
public long CreatedTimeStamp { get; set; }
}
[DataContract]
public class RootObject
{
[DataMember(Name="abcDetails")]
public List<Detail> Details { get; set; }
}
And to test:
string json = #"
{
""abcDetails"":[
{
""screenName"":""my name"",
""text"":""tweet desc"",
""createdTime"":1423494304000,
""entities"":{ },
""name"":""abc"",
""id"":""123""
}]
}
";
var response = DataContractJsonSerializerHelper.GetObject<RootObject>(json);
foreach (var detail in response.Details)
{
Console.WriteLine(string.Format("Created Time: {0}; Text: \"{1}\"", detail.CreatedTimeStamp, detail.Text));
}
produces the output
Created Time: 1423494304000; Text: "tweet desc"
using the helper class:
public static class DataContractJsonSerializerHelper
{
public static T GetObject<T>(string json) where T : class
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
return GetObject<T>(json, serializer);
}
public static T GetObject<T>(string json, DataContractJsonSerializer serializer)
{
using (var stream = GenerateStreamFromString(json))
{
var obj = serializer.ReadObject(stream);
return (T)obj;
}
}
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
}

Categories

Resources