Deserialize JSON dictionary - c#

I have universal app where I communicate with REST API. Any response from REST I deserialize with DataContractJsonSerializer.
I have a problem with response that contains dictionary. This dictionary I don't need deserialize - my class doesn't contains this dictionary. In Win RT it works, but in Win Phone it doesn't works. I get this error:
The dictionary cannot be deserialized because the member 'key of dictionary' was found more than once in the input.
I don't understand why it works in Win RT and not in Win Phone.
//edit - add sample JSON
{
"ResultType": 0,
"Message": "",
"Exception": null,
"Result": {
"property": 1,
"property2": 2,
"property3": "2015-01-31T13:56:43.5337609+01:00",
"GeneratedQuestions": {
"className": [
{
"innerProperty": 1,
"innerProperty2": 2,
"innerProperty3": "sample",
"innerProperty4": [
{
"prop1": 1,
"prop2": 2,
"prop3": 3,
"prop4": "sample text",
}
]
},
{
"innerProperty": 1,
"innerProperty2": 2,
"innerProperty3": "sample2",
"innerProperty4": []
},
{
"innerProperty": 1,
"innerProperty2": 2,
"innerProperty3": "sample3",
"innerProperty4": []
}
]
}
}
}
code for deserialize json
protected T DeserializeJson<T>(string json)
where T : class
{
T type;
DataContractJsonSerializer jsonSerialized = new DataContractJsonSerializer(typeof(T), new DataContractJsonSerializerSettings { DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("dd.mm.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture) });
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
try
{
ms.Position = 0;
type = jsonSerialized.ReadObject(ms) as T;
}
catch
{
type = default(T);
}
}
return type;
}
Simplified version of Model:
[DataContract]
public class SampleClass
{
[DataMember(Name = "ResultType")
public string ResultType { get; set; }
[DataMember(Name = "Message")
public string Message{ get; set; }
[DataMember(Name = "Exception")
public Exception Exception{ get; set; }
[DataMember(Name = "Result")
public ResultModel Result{ get; set; }
}
public class ResultModel
{
[DataMember(Name = "property")
public int Property { get; set; }
[DataMember(Name = "property2")
public int Property2 { get; set; }
[DataMember(Name = "property3")
public string Property3 { get; set; }
}

I think the error lies in the missing [DataContract]-attribute on ResultModel which tells the serializer to serialize all public members:
Apply the IgnoreDataMemberAttribute attribute to opt-out of the default DataContractSerializer behavior. By default, the DataContractSerializer serializes all publicly visible types. All public read/write properties and fields of the type are serialized. You can change the default behavior by applying the DataContractAttribute and DataMemberAttribute attributes to the types and members
So either put that [DataContract]-attribute on ResultModel or mark GeneratedQuestions as [IgnoreDataMember].
Well the latter is no option for you as you don't have that property in your model. Just to mention that second option.

Related

How to deserialise or format WebAPI result into specific json structure

I was working with a .net core 3.1 Web API. Which is getting data from an external API. Following is my code Controller part
[HttpGet("transinfo/{id}")]
public Object GettransactionData(int id)
{
var result=_transaction.GettransactionDetails(id).Result;
List<PipeLineResponse> P = JsonConvert.DeserializeObject<List<PipeLineResponse>>(result.ToString());
PipeLineResponseObject P1 = new PipeLineResponseObject();
P1.data = P;
return P1;
}
And my service code as follows
public async Task<Object> GettransactionDetails(int id)
{
string request=//fetched from db
var stringContent = new StringContent(request);
Client = utilities.GetHttpClient();
string apiEndpoint=//External API URL
HttpResponseMessage httpResponseMessage = await Client.PostAsync(apiEndpoint, stringContent);
if (httpResponseMessage.IsSuccessStatusCode)
{
return await httpResponseMessage.Content.ReadAsAsync<Object>();
}
}
But i am getting the result in following format (response from postman)
{
"data": [
{
"Tranid": "34540d40-7db8-44c1-9a2a-5072c2d01756",
"fields": {
"Fields.10": "1001",
"Fields.11": "Test1",
"Fields.12": "Fixed1"
}
},
{
"Tranid": "145800f9-c4a5-4625-84d7-29af5e674a14",
"fields": {
"Fields.10": "1002",
"Fields.11": "Test2",
"Fields.12": "Fixed2"
}
}
]
}
But i need the data in following format
{
"data": [
{
"TransactionID": "34540d40-7db8-44c1-9a2a-5072c2d01756",
"fieldsList": [
{
"fieldId": "10",
"fieldValue": "1001"
},
{
"fieldId": "11",
"fieldValue": "Test1"
},
{
"fieldId": "12",
"fieldValue": "Fixed1"
}
]
},
{
"TransactionID": "145800f9-c4a5-4625-84d7-29af5e674a14",
"fieldsList": [
{
"fieldId": "10",
"fieldValue": "1002"
},
{
"fieldId": "11",
"fieldValue": "Test2"
},
{
"fieldId": "12",
"fieldValue": "Fixed2"
}
]
}
]
}
How can i achieve this ? is possible to deserialise using JObject or JArray? Please help.
i have tried to create following model class and tried to deserialise but not getting result as expected.
public class PipeLineResponse
{
public string TransactionID { get; set; }
public List<Dictionary<string, string>> fields { get; set; }
}
public class PipeLineResponseObject
{
public List<PipeLineResponse> data { get; set; }
}
How to create that json in that format any DTO or Automapper will work ? Please help me with samples.
The solution that I am laying down here takes the DTO approach. The response from the service is being deserialized to the DTO, which further is being manually mapped to the final ViewModel that we are sending to the client. By no means, this implementation is production-ready and there is scope for improvement, for which I am adding in comments. But this gives a detailed understanding of how we can handle these kind of scenarios. We are making use of Newtonsoft.Json, which can be pulled into your project via the NuGet package manager.
Structure of the DTO
// RootDTO.cs
// This structure is directly based on the response obtained from remote service.
public class Fields
{
[JsonProperty(PropertyName ="Fields.10")]
public string Fields10 { get; set; }
[JsonProperty(PropertyName = "Fields.11")]
public string Fields11 { get; set; }
[JsonProperty(PropertyName = "Fields.12")]
public string Fields12 { get; set; }
}
public class Datum
{
public string Tranid { get; set; }
public Fields fields { get; set; }
}
public class RootDTO
{
[JsonProperty(PropertyName ="data")]
public List<Datum> data { get; set; }
}
Structure of ViewModel
// PipelineResponse.cs
public class FieldsList
{
public string fieldId { get; set; }
public string fieldValue { get; set; }
}
public class ResponseDatum
{
[JsonProperty(PropertyName = "TransactionID")]
public string TransactionID { get; set; }
public List<FieldsList> fieldsList { get; set; }
}
public class PipelineResponse
{
public List<ResponseDatum> data { get; set; }
}
Deserializing the response to the DTO
// ...other code
var responseString = await httpResponseMessage.Content.ReadAsAsync<Object>();
// This is where the DTO object is created. This should be mapped to view model type.
var responseDTO = JsonConvert.DeserializeObject<RootDTO>(responseString);
Mapping the DTO to ViewModel
The mapping from DTO type to ViewModel type needs to be done before sending the response to the client. It is the view model type that is sent to the client. This logic can be placed within a separate helper (ideally, to separate concerns) or any other location as per the practices you are following.
public PipelineResponse ConvertResponseDTOToResponse(RootDTO responseDTO)
{
// FieldId is being hardcoded here. Instead, you can use Reflection to
// fetch the property name, split on '.' and take the item at index 1.
// Notice that DTO properties have "JsonProperty" attributes for this.
try
{
List<ResponseDatum> responseList = new List<ResponseDatum>();
if (responseDTO != null)
{
// Reflection can be used to avoid hardcoding on 'fieldId'
foreach (var item in responseDTO.data)
{
var responseDataObj = new ResponseDatum
{
TransactionID = item.Tranid,
fieldsList = new List<FieldsList>
{
new FieldsList
{
fieldValue = item.fields.Fields10,
fieldId = "10"
},
new FieldsList
{
fieldValue = item.fields.Fields11,
fieldId = "11"
},
new FieldsList
{
fieldValue = item.fields.Fields12,
fieldId = "12"
}
}
};
responseList.Add(responseDataObj);
}
}
// This object is what you return from your controller endpoint finally.
// The serialized response of this object is of the json structure you need
return new PipelineResponse { data = responseList };
}
catch (Exception ex)
{
throw ex;
}
}

Deserializing JSON with Child and Inner Childs

I am familiar with JSON.net a bit and can Deserialize the JSON with basic structure (upto one child). I am currently in process of Deserializing the JSON that is returned from Netatmo API. The structure of JSON is complicated for me. Following is the basic structure of the JSON,
_id
place
location
Dynamic Value 1
Dynamic Value2
altitude
timezone
mark
measures
Dynamic Value 1
res
Dynamic Value 1
Dynamic Value 1
Dynamic Value 2
type
Dynamic Value 1
Dynamic Value 2
modules
Dynamic Value 1
Dynamic Value 1 and Dynamic Value 2 represents the values that is changed for each id. The complete JSON is given below,
{
"body": [{
"_id": "70:ee:50:02:b4:8c",
"place": {
"location": [-35.174779762001, -5.8918476117544],
"altitude": 52,
"timezone": "America\/Fortaleza"
},
"mark": 0,
"measures": {
"02:00:00:02:ba:2c": {
"res": {
"1464014579": [16.7, 77]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:02:b4:8c": {
"res": {
"1464014622": [1018.1]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:02:ba:2c"]
}, {
"_id": "70:ee:50:12:40:cc",
"place": {
"location": [-16.074257294385, 11.135715243973],
"altitude": 14,
"timezone": "Africa\/Bissau"
},
"mark": 14,
"measures": {
"02:00:00:06:7b:c8": {
"res": {
"1464015073": [26.6, 78]
},
"type": ["temperature", "humidity"]
},
"70:ee:50:12:40:cc": {
"res": {
"1464015117": [997]
},
"type": ["pressure"]
}
},
"modules": ["02:00:00:06:7b:c8"]
}],
"status": "ok",
"time_exec": 0.010364055633545,
"time_server": 1464015560
}
I am confused by looking at the complex structure of this JSON. For single level of JSON I have used this code in the past,
IList<lstJsonAttributes> lstSearchResults = new List<lstJsonAttributes>();
foreach (JToken objResult in objResults) {
lstJsonAttributes objSearchResult = JsonConvert.DeserializeObject<lstJsonAttributes>(objResult.ToString());
lstSearchResults.Add(objSearchResult);
}
But for so many child I have yet to understand how the object class will be created. Any guidance will highly appreciated.
Update:
This is what I have achieved so far.
I have created a main class as below,
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public string mark { get; set; }
public List<string> modules { get; set; }
}
and "Place" class is as follow,
public class PublicData_Place
{
public List<string> location { get; set; }
public string altitude { get; set; }
public string timezone { get; set; }
}
Then I have Deserialized the object in the following code line,
var obj = JsonConvert.DeserializeObject<List<PublicDataClass>>(jsonString);
I can now successfully get all the data except the "measures" which is little bit more complicated.
Using json.net, JSON objects that have arbitrary property names but fixed schemas for their values can be deserialized as a Dictionary<string, T> for an appropriate type T. See Deserialize a Dictionary for details. Thus your "measures" and "res" objects can be modeled as dictionaries.
You also need a root object to encapsulate your List<PublicDataClass>, since your root JSON container is an object like so: { "body": [{ ... }] }.
Thus you can define your classes as follows:
public class RootObject
{
public List<PublicDataClass> body { get; set; }
public string status { get; set; }
public double time_exec { get; set; }
public int time_server { get; set; }
}
public class PublicDataClass
{
public string _id { get; set; }
public PublicData_Place place { get; set; }
public int mark { get; set; }
public List<string> modules { get; set; }
public Dictionary<string, Measure> measures { get; set; }
}
public class PublicData_Place
{
public List<double> location { get; set; } // Changed from string to double
public double altitude { get; set; } // Changed from string to double
public string timezone { get; set; }
}
public class Measure
{
public Measure()
{
this.Results = new Dictionary<string, List<double>>();
this.Types = new List<string>();
}
[JsonProperty("res")]
public Dictionary<string, List<double>> Results { get; set; }
[JsonProperty("type")]
public List<string> Types { get; set; }
}
Then do
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
var obj = root.body;
I've worked with XML for a few years and my change to JSON structure I've got a little confused too, always that I want to see how an object look like I use this web site jsoneditoronline Just copy and paste your JSON and click on arrow to parse to an object, I hope it helps until you get used to JSON structure.

Convert Json property based on property value

I would like to deserialize a json to object. The json is like below. But one property value maybe string or array, does anyone know how to handle this?
{
"name": "123", //Name
"properties": [
{
"propertyId": "Subject", // property id
"value": [
{
"entityId": "math", //entity id
"entityTypeId": "MATH" //entity type id
}
]
},
{
"propertyId": "Description",
"value": "Hello World."
}
]
}
The class is like below.
//The object
public class Content
{
public Content()
{
//Properties is List.
Properties = new List<Property>();
}
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "properties")]
public List<Property> Properties { get; set; }
}
public class Property
{
public Property()
{
Value = new List<Value>();
}
[JsonProperty(PropertyName = "propertyId")]
public string PropertyDefId { get; set; }
//Actually this property value can also be string, that's the problem.
[JsonProperty(PropertyName = "value")]
public List<Value> Value { get; set; }
}
//Value object
public class Value
{
//Have to write comments.
[JsonProperty(PropertyName = "entityId")]
public string EntityId { get; set; }
//Have to write comments.
[JsonProperty(PropertyName = "entityTypeId")]
public string EntityTypeId { get; set; }
}
I've done this in Java with Gson liblary and it was like
JsonObject field = parser.parse(json).getElementAsJSONObject();
if (field.isPrimitive()) {
String text = field.asString();
} else if (field.isArray()) {
JSONArray array = field.asArray();
}
I wrote this code from my memory so not 100% reliable. I don't know any solution for C# though.
$.parseJSON will convert your string to the correct object even if the property type is different for two different properties.
http://jsfiddle.net/mdanielc/e0acsyp1/2/
var jsonString = '{"name": "123","properties": [{"propertyId": "Subject","value": [{"entityId":"math","entityTypeId": "MATH" }]},{"propertyId": "Description","value": "Hello World."}]}';
var jsonobj = $.parseJSON(jsonString);
alert(jsonobj.properties[0].value[0].entityId);
alert(jsonobj.properties[1].value);
});

How to deserialize JSON to my custom Class

Im new to JSON (and not sure if its the right way to do that), my problem is to deserialize my classes, all models implements this interface:
public interface IPersistent
{
object Id { get; set; }
}
Example of class:
public class ModelTest : IPersistent
{
private int? _id;
public object Id
{
get { return this._id; }
set { this._id = (int?)value; }
}
public string Name { get; set; }
}
Serialize method:
public void SerializeData<T>(T[] data)
{
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
DateFormatHandling = DateFormatHandling.IsoDateFormat
};
var result = JsonConvert.SerializeObject(data, Formatting.Indented, settings);
//more things happen, but not affect serialized data.
}
Deserialize method:
public T[] DeserializeData<T>(string objCached)
{
var settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
DateFormatHandling = DateFormatHandling.IsoDateFormat
}; //not sure if a need this settings, but...
T[] result = JsonConvert.DeserializeObject<T[]>(objCached, settings); //error here.
return result;
}
Error:
Message=Specified cast is not valid.
objCached data:
[
{
"$id": "1",
"Id": 1000,
"Name": "Name 1"
},
{
"$id": "2",
"Id": 2000,
"Name": "Name 2"
},
{
"$id": "3",
"Id": 3000,
"Name": "Name 3"
},
{
"$id": "4",
"Id": 4000,
"Name": "Name 4"
}
]
I tried validate JSON result using:
http://json2csharp.com/
Result:
public class RootObject
{
public string __invalid_name__$id { get; set; }
public int Id { get; set; }
public string Name { get; set; }
}
I'm looking for something that changes just the methods (Serialize and Deseriaize), can't change ALL my models (its a legacy without any unit test).
All you need to do is changing the set method of Id property. (Because value is long when read from json, which can not be casted toint?)
public class ModelTest : IPersistent
{
private int? _id;
public object Id
{
get { return this._id; }
set { this._id = new Nullable<int>((int)(long)value); }
}
public string Name { get; set; }
}

Newtonsoft JSON Deserialize AND jsonfreeze

I have a two simple PHP class
class Order{
public $orderNo;
public $lines = array();
public $paid = false;
public function addLine(OrderLine $line) {
$this->lines[] = $line;
}
public function setPaid($paid = true) {
$this->paid = true;
}
}
class OrderLine{
public function __construct($item, $amount){
$this->item = $item;
$this->amount = $amount;
}
public $item;
public $amount;
public $options;
}
Serialize object uses https://github.com/mindplay-dk/jsonfreeze
...
$json = new JsonSerializer;
$data = $json->serialize($order);
Have output:
{
"#type": "Order",
"orderNo": 123,
"lines": [{
"#type": "OrderLine",
"item": "milk \"fuzz\"",
"amount": 3,
"options": null
},{
"#type": "OrderLine",
"item": "cookies",
"amount": 7,
"options": {
"#type": "#hash",
"flavor": "chocolate",
"weight": "1\/2 lb"
}
}],
"paid": true
}
Send the string XMLRPC in VB.NET
As using Newtonsoft JSON get a live object?
As well as how to create a compatible format by analogy with the json string of living VB.net OR C# object?
Here's something you could start with. You create some classes with properties which represent the JSON Format (untested code, just as idea):
public class MyData
{
[JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("#orderNo")]
public int OrderNo { get; set;
[JsonProperty("paid")]
public bool Paid { get; set; }
[JsonProperty("lines")]
public List<MyDataLine> Lines { get; set; }
}
public class MyDataLines
{
[JsonProperty("#type")]
public string Type { get; set; }
[JsonProperty("options")]
public MyDataLinesOptions Options { get; set; }
// ... more
}
public class MyDataLinesOptions
{
// ... more
}
Then you can serialize and deserialize the the data like this:
string json = "the json data you received";
MyData myData = JsonConvert.DeserializeObject<MyData>(json);
// ...
json = JsonConvert.SerializeObject(myData);
"#type": "Order"
and
"#type": "OrderLine",
this is not a property, this is an indication of the type of the object

Categories