Deserialize JSON response with unknown object names using c# ReadObject() - c#

So i'm trying to deserialise a JSON response implicitly back into a object instance using the following code.
DataContractJsonSerializer jsonSerialiser = new DataContractJsonSerializer(responseType);
responseBase = jsonSerialiser.ReadObject(responseStream);
The response if piped out as a string looks as follows
{
"20170317112739": {
"start": {
"SQ": 4577,
"TS": "2017-03-17T11:26:59",
"FisCode": "_R1-AT1_001/1_SQ4577_2017-03-17T11:26:59_0,00_0,00_0,00_0,00_0,00_vr1zl86Y_49e862eb_rNvvLM3FKh4=_DGZt+z+A3fY8zLlt2E55R8zCD/wf7yw9q/VivAiaNtxNpaTkhlTONAsD6yc+8Vcxwnm/lBalIwEI6GswC04kqg=="
},
"close": {
"SQ": 4667,
"TS": "2017-03-17T11:27:39",
"FisCode": "_R1-AT1_001/1_SQ4667_2017-03-17T11:27:16_0,00_0,00_0,00_0,00_0,00_r/82sV+w_49e862eb_FD/gDnivnes=_LKmvkk5OEoL7EFIebQU73VDVfPGzRGOyKNLlIW1mJkvPpqS0oVdWmqiNGR0cnpT35ArF++XzO1D/q7keTJe4cA=="
}
},
"current": {
"start": {
"SQ": 4670,
"TS": "2017-03-17T11:27:39",
"FisCode": "_R1-AT1_0/1_SQ4670_2017-03-17T11:27:39_0,00_0,00_0,00_0,00_0,00_/agx6rsw_49e862eb_qTh1/lCawvo=_f7yNP/+WUWZCojerZ9fe/wID1gll0I37swEKsauV8h7g8gSCFZ2Ykg45JjkO7BrChCBkl0ewohuGdbP4haLbrQ=="
},
"2017-03": {
"SQ": 4673,
"TS": "2017-03-17T11:27:39",
"FisCode": "_R1-AT1_0/1_SQ4670_2017-03-17T11:27:39_0,00_0,00_0,00_0,00_0,00_/agx6rsw_49e862eb_qTh1/lCawvo=_f7yNP/+WUWZCojerZ9fe/wID1gll0I37swEKsauV8h7g8gSCFZ2Ykg45JjkO7BrChCBkl0ewohuGdbP4haLbrQ=="
}
},
"lic": "0SvXs"
}
Simple responses from the JSON service are no problem i can simply decorate these with [DataContract] and [DataMember].
The problem with this particular service response is that item names such as "2017-03" will change depending on when the call is made to during other months/years.
How do i deal with this in C#?, can someone supply an example of how my class should look?
For the life of me i cannot get this data into my object class!

You can have a dynamic dictionary as suggested in this post Deserialize JSON into C# dynamic object?
Or you can implement something like this with the help of System.Web.Helpers
using (StreamReader r = new StreamReader("sample.json"))
{
string json = r.ReadToEnd();
dynamic data = Json.Decode(json);
Console.WriteLine(data["20170317112739"].start.sq);
}
Here sample.json contains your sample JSON response.

Related

How to access Json (which was a result of HttpMessage) in C#?

I am writing two applications (Web API's) in .NET . From the app A I want to call a method in Controller of app B using Http Request.
Here
using (var askPensionerDetails = new HttpClient())
{
double pensionToDisburse = 0;
askPensionerDetails.BaseAddress = new Uri("http://localhost:55345/api/pensionerdetails/");
var responseTask = askPensionerDetails.GetAsync("getById?pan=" + inputOfPensioner.PAN);
responseTask.Wait();
var result =responseTask.Result ;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadFromJsonAsync<object>();
readTask.Wait();
return Ok(readTask.Result);
}
}
The output for this in postman is
{
"name": "bunk seenu",
"dateOfBirth": "1990-01-02T00:00:00",
"pan": "ABCD12351E",
"salaryEarned": 45000,
"allowances": 500,
"pensionType": 1,
"bankDetails": {
"bankName": "SBI",
"accountNumber": "SBI00001BS",
"bankType": 0
}
}
That was a desired output. But the problem is how to access the properties like bankdetails,name,pan,salaryEarned.
I have tried using readTask.Result["name"] but it is throwing error.
I have also tried using result.Content.ReadAsStringASync();
But the output in postman is
{
"name": [],
"dateOfBirth": [],
"pan": [],
"salaryEarned": [],
"allowances": [],
"pensionType": [],
"bankDetails": [
[
[]
],
[
[]
],
[
[]
]
]
}
I don't have class associated with the result type of Json for statement readTask = result.Content.ReadFromJsonAsync(); (As per design constraints).
From the docs:
If you have JSON that you want to deserialize, and you don't have the class to deserialize it into, you have options other than manually creating the class that you need:
Deserialize into a JSON DOM (document object model) and extract what you need from the DOM.
The DOM lets you navigate to a subsection of a JSON payload and deserialize a single value, a custom type, or an array. For information about the JsonNode DOM in .NET 6, see Deserialize subsections of a JSON payload. For information about the JsonDocument DOM, see How to search a JsonDocument and JsonElement for sub-elements.
Use the Utf8JsonReader directly.
Use Visual Studio 2019 to automatically generate the class you need:
Copy the JSON that you need to deserialize.
Create a class file and delete the template code.
Choose Edit > Paste Special > Paste JSON as Classes. The result is a class that you can use for your deserialization target.
You can use Newtonsoft.Json
JObject jo = JObject.Parse(readTask.Result);
var name = jo["name"];
if(string.IsNnullOrEmpty(name)){
///some code
}

Sometimes yes and sometimes not JSON error: "No parameterless constructor defined for type of 'System.String'"

Here's my code:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, string> responseVals = serializer.Deserialize<Dictionary<string, string>>(response);
When response is
{
"status": 21007
}
it works.
When response is
{
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "...",
"application_version": "1.0",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "...",
"receipt_creation_date_ms": "...",
"receipt_creation_date_pst": "...",
"request_date": "...",
"request_date_ms": "...",
"request_date_pst": "...",
"original_purchase_date": "...",
"original_purchase_date_ms": "...",
"original_purchase_date_pst": "...",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "...",
"transaction_id": "...",
"original_transaction_id": "...",
"purchase_date": "...",
"purchase_date_ms": "...",
"purchase_date_pst": "...",
"original_purchase_date": "...",
"original_purchase_date_ms": "..",
"original_purchase_date_pst": "...",
"is_trial_period": "false"
}
]
},
"status": 0,
"environment": "Sandbox"
}
I get an error:
No parameterless constructor defined for type of 'System.String'
Why the difference?
This is in a web service (Asp.net) verifying an iOS in app purchase (in sandbox). Perhaps this matters.
Why the difference?
Your first example is working because you are passing primitive data
to deserialize into Dictionary<string, string>, but in second example you are trying to convert custom
object i.e receipt to string which is not prossible
If you want to deserialize specific property then you can convert this json string to JObject and then use that property to get the value
string json = #"{
status: '20122',
OS: [
'Windows',
'macintosh'
]
}";
JObject obj = JObject.Parse(json);
Console.WriteLine(obj["status"]); //20122
.Net fiddle
One of the major advantages of Json decoders, is that they generally ignore any fields that are present in the json, but not in the deserialised class.
If you just want status and ignore all the rest, you can do this:
public class Data
{
public string Status {get;set;}
}
public void A()
{
Data data = Newtonsoft.Json.JsonConvert.DeserializeObject<Response>(response);
}
The second response will not be deserialized into a dictionary, you can try desirialize it to object.
object objClass = Newtonsoft.Json.JsonConvert.DeserializeObject<object>(response);
or create your own object and deserialize to it.
You can use from Json to classes, it will generate classes based on your json structure.

Converting a string to a JSON for a HTTP POST request

I'm trying to return a json file from a HTTP POST request from Slack. I am using netcoreapp3.1 along with the Newtonsoft.Json NuGet. Right now my HTTP POST function looks like this.
public async Task<ActionResult> SlashCommand([FromForm] SlackSlashCommand request)
{
var retVal = new JsonResult(GetBlock());
return retVal;
}
GetBlock() is a function that returns a class that I created. This works currently, but everytime I want to modify the json that it returns, I have to modify that class. I would really love to just have a json in string format that I can copy and paste into my code and then return to Slack in json format.
Is there a way to do this? I've been trying to use JsonConvert.DeserializeObject(str); but I'm using it incorrectly. From what I understand, that function takes in an string and converts it to an object. I need to take in a string and convert it to a Microsoft.AspNetCore.Mvc.ActionResult json.
Any help? Thanks.
An alternative option is to use an anonymous type, which will be less vulnerable to becoming invalid JSON (a simple typo in your JSON string could render the entire block of JSON unreadable):
var data = new
{
blocks = new object[] {
new {
type = "section",
text = new {
type = "plain_text",
text = "Hello!",
emoji = true
}
},
new {
type = "divider"
},
new {
type = "actions",
elements = new object[] {
new {
type = "button",
text = new {
type = "plain_text",
text = "Help"
},
value = "helpButton"
}
}
}
}
};
return new JsonResult(data);
Produces:
{
"blocks": [
{
"type": "section",
"text":
{
"type": "plain_text",
"text": "Hello!",
"emoji": true
}
},
{
"type": "divider"
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text":
{
"type": "plain_text",
"text": "help"
},
"value": "helpButton"
}
]
}
]
}
Try it online
I found an answer.
This is my JSON in string format:
string str = "{\"blocks\": [{\"type\": \"section\",\"text\": {\"type\": \"plain_text\",\"text\": \"Hello!\",\"emoji\": true}},{\"type\": \"divider\"},{\"type\": \"actions\",\"elements\": [{\"type\": \"button\",\"text\": {\"type\": \"plain_text\",\"text\": \"Help\"},\"value\": \"helpButton\"}]}]}";
And then this is my function:
public async Task<ActionResult> SlashCommand([FromForm] SlackSlashCommand request)
{
var retVal = new JsonResult(JsonConvert.DeserializeObject<object>(str));
return retVal;
}
This works quite well. Sorry if I didn't give too much info.

Json Serialize and Deserialize Multiple Object

The solution may be exist, but I tried few things online but i am not able to find relevant solution. Here is my scenario. I wanted to pass two models to Serialize(I user Json.JsonConvert.SerializeObject) In order to send to my API. What I done so far
On the Client: I have mOrder (Order Model) and mOPLog (Log Model). Both I have combined in to one and Send to Json Serializer then to my API
var data = new
{
DataTable1 = mOrder,
DataTable2 = mOPLog
};
string sUrl = GlobalParameters.Host + "api/Order/UpdateOrderWithLog";
string sResult = HttpHelper.httpPut(sUrl, Newtonsoft.Json.JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented));
Then on the Api Controller side I have declare Like this.
public Models.ApiResult UpdateOrderWithLog(dynamic data)
{
Models.Order model = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Order>(data.ChildrenTokens[0].First);
Its throws the error when I deserialize and bind with my model. I can receive the Data on API Controller. Here is the data, how is looks like.
{{
"DataTable1": {
"OrderID": "0000006915",
"GroupID": "0000000001",
"GroupCode": "WG01",
"GroupName": "MatGroup",
"ShiftID": "0000000001",
"ShiftCode": "WS01",
"ShiftName": "DayShift",
"OrderDate": "2019-03-08T10:25:09.243",
"OrderNO": "0000006915",
"Memo": "Test123",
"OrderDetail": [
{
"OrderDetailID": "0000007103",
"OrderID": "0000006915",
"SourceType": "IQR",
"SourceID": "0000126061",
"Memo": "",
"Accept": false
},
{
"OrderDetailID": "0000007104",
"OrderID": "0000006915",
"SourceType": "IQR",
"SourceID": "0000126062",
"Memo": "",
"Accept": false
}
]
},
"DataTable2": {
"LogID": null,
"LogType": "Update",
"OperatorName": "admin",
"OperatingTime": "2019-03-13T05:53:43.5940133+08:00",
"OperationType": "Order",
"Operation": "0000006915",
"OperationContent": "",
"OperatingSystem": "Win10",
"TerminalName": "DH01",
"IPAddress": "192.168.16.124"
}
}}
But systems throws "The remote server returned an error: (500) Internal Server Error" I am not sure, where I am making mistake. If anyone come across Json Serializing and De serializing multiple object. Any help will greatly appreciated. Thanks
Update:
I Created a class with dynamic model, then send that one to API Controller.
public class LogDyModel
{
public dynamic m1 { get; set; }
public dynamic m2 { get; set; }
}
on my Client i bind my model with this dynamic and send to my API Controller
Models.LogDyModel data = new Models.LogDyModel();
data.m1 = mOrder;
data.m2 = mOPLog;
On my API Controller
public Models.ApiResult UpdateOrderWithLog(Models.LogDyModel data)
{
var deserial = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.LogDyModel>(Newtonsoft.Json.JsonConvert.SerializeObject(data));
Models.Order model = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.Order>(Newtonsoft.Json.JsonConvert.SerializeObject(deserial.m1));
Models.OpLog mLog = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.OpLog>(Newtonsoft.Json.JsonConvert.SerializeObject(deserial.m2));
Now all is sorted as I wanted. Hope this will help someone looking similar issue. Thanks for the support whoever trying to check and help me out.

Parsing a JSON dictionary that contains the same key with different casing

I have a problem;
I would to know if there is a method to parse json file without having a unique format. So it may have different attributes but all of them contain the attribute Status but it can be in double.
{
"requestid": "1111",
"message": "db",
"status": "OK",
"data": [
{
"Status": "OK", // this one I would to test first to read the other attributes
"fand": "",
"nalDate": "",
"price": 1230000,
"status": 2
}
]
}
With https://www.newtonsoft.com/json
Data data = JsonConvert.DeserializeObject<Data>(json);
And create the class Data with the interesting data inside the json
The defacto standard Json serializer for .NET is Newtonsoft.Json (How to install). You can parse the Json into an object graph and work on that in any order you like:
namespace ConsoleApp3
{
using System;
using Newtonsoft.Json.Linq;
class Program
{
static void Main()
{
var text = #"{
'requestid': '1111',
'message': 'db',
'status': 'OK',
'data': [
{
'Status': 'OK', // this one I would to test first to read the other attributes
'fand': '',
'nalDate': '',
'price': 1230000,
'status': 2
}
]
}";
var json = JObject.Parse(text);
Console.WriteLine(json.SelectToken("data[0].Status").Value<string>());
Console.ReadLine();
}
}
}

Categories

Resources