How to parse JSON with dynamic variables in C# - c#

I've tried multiple ways of doing this and can't seem to find the proper solution. The JSON I am trying to parse looks like this
{
"data":
{
"random1":
{
"language": "en",
"state": "fl"
},
"completelyrandom":
{
"language": "fr",
"state": "wa"
}
}
}
Currently I am using the below JSON.NET to deserialize into a dynamic object, which gives me access to "language", "state" but I don't know what the parent object is.
var jsonSerializer = new JsonSerializer();
dynamic value = jsonSerializer.Deserialize(new JsonTextReader(new StringReader(json)));
foreach (var obj in value.data)
{
var myObj = obj.First;
string language = myObj.language;
}
How do I get access to "random1" and "completelyrandom"

Yeah, writing all of it out cleared my head. obj.Name gives my the container.

Related

Get Value From JSON File stored in Azure Storage Using C#

I have JSON file in Azure Storage which I am reading using C#. In that JSON file there is anode called SQLViewDifinition and that node I have SQL which I need to fetch.
I have read the file into a string and converted that string in JObject. I have the JSON now but is finding it difficult to read that particular node. Tried with JToken and Jproperty. But could not crack it.
JSON file looks like this:
{
"jsonSchemaSemanticVersion": "1.4.0",
"imports": [
{
"corpusPath": "cdm:/foundations.cdm.json"
},
{
"corpusPath": "localCdm:/foundations.cdm.json"
}
],
"definitions": [
{
"entityName": "METCredManCollectionGroupEntity",
"exhibitsTraits": [
{
"traitReference": "is.CDM.entityVersion",
"arguments": [
{
"name": "versionNumber",
"value": "1.0.0"
}
]
},
{
"traitReference": "has.sqlViewDefinition",
"arguments": [
{
"name": "sqlViewDefinition",
"value": "CREATE VIEW [DBO].[METCREDMANCOLLECTIONGROUPENTITY] AS SELECT T1.COLLECTIONGROUPID AS COLLECTIONGROUPID, T1.DESCRIPTION AS DESCRIPTION, T1.RECID AS CREDMANCOLLECTIONGROUPTABLERECID, T1.DATAAREAID AS CREDMANCOLLECTIONGROUPTABLEDATAAREAID, T1.RECVERSION AS RECVERSION, T1.PARTITION AS PARTITION, T1.RECID AS RECID FROM CREDMANCOLLECTIONGROUPTABLE T1"
}
]
},
{
"traitReference": "has.backingElements",
"arguments": [
{
"name": "backingElements",
"value": "CredManCollectionGroupTable"
}
]
}
],
"hasAttributes": [
{
"name": "CollectionGroupId",
"dataType": "CredManCollectionGroupId",
"isNullable": true,
"displayName": "Collection group",
"maximumLength": 10
},
{
"name": "Description",
"dataType": "Description",
"isNullable": true,
"displayName": "Description",
"maximumLength": 60
},
{
"name": "CredmanCollectionGroupTableRecId",
"dataType": "other",
"isNullable": true,
"displayName": "Record-ID"
},
{
"name": "CredmanCollectionGroupTableDataAreaId",
"dataType": "other",
"isNullable": true,
"displayName": "Company"
}
],
"displayName": "MET Collection groups (Shared)"
},
{
"explanation": "Collection group",
"dataTypeName": "CredManCollectionGroupId",
"extendsDataType": "SysGroup"
},
{
"explanation": "Group",
"dataTypeName": "SysGroup",
"extendsDataType": "string"
},
{
"explanation": "Description",
"dataTypeName": "Description",
"extendsDataType": "string"
}
]
}
I need to find sqlViewDefinition from this file.
So far I can read the JSON in a JSON object. But could not find a way to get the view definition.
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Nancy.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class FindFiles
{
// Main Method with int return type
static int Main(String[] args)
{
Console.WriteLine("Buid SQL");
// for successful execution of code
return X("FILE_NAME");
}
public static int X(string fileName)
{
//connection string
string storageAccount_connectionString = "CONNECTION_STRING";
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccount_connectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("CONTAINER");
//The specified container does not exist
try
{
//root directory
CloudBlobDirectory dira = container.GetDirectoryReference(string.Empty);
//true for all sub directories else false
var rootDirFolders = dira.ListBlobsSegmentedAsync(true, BlobListingDetails.Metadata, null, null, null, null).Result;
foreach (var blob in rootDirFolders.Results)
{
if (blob.Uri.OriginalString.Contains(fileName, StringComparison.OrdinalIgnoreCase) && blob.Uri.OriginalString.Contains(".cdm.json", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("Blob: " + blob.Uri.OriginalString);
if (blob.GetType() == typeof(CloudBlockBlob))
{
CloudBlockBlob b = (CloudBlockBlob)blob;
string jsonText = b.DownloadTextAsync().Result;
Dictionary<string, object> json_Dictionary = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(jsonText.ToString());
JObject json = JObject.Parse(jsonText);
}
}
}
}
catch (Exception e)
{
// Block of code to handle errors
Console.WriteLine("Error", e);
}
return 1;
}
}
As you are using .NET 6 and because the structure is always the same, the easiest way to deserialize is to mimic the structure of the JSON in C# classes. You can then easily deserialize the JSON into objects and access the properties of the objects instead of "brachiating" through dynamic data.
In order to get the classes, you can use Visual Studio's Paste Special function (Edit -> Paste special -> Paste JSON as classes). This generates the classes for you (you can adjust the classes if you don't need parts of them or change the casing of the property names; also you can use attributes to customize the serialization).
Afterwards, it is easy to parse the JSON into an object, e.g. (I've put your sample JSON into the jsonContent variable):
var obj = System.Text.Json.JsonSerializer.Deserialize<Rootobject>(jsonContent);
Because it still is a complex structure, getting to the SQL needs a bit of code:
Console.WriteLine(obj
.definitions[0]
.exhibitsTraits
.Where(x => x.traitReference == "has.sqlViewDefinition")
.First().arguments.Where(x => x.name == "sqlViewDefinition")
.First().value);
Finally, the above code writes the following output:
CREATE VIEW [DBO].[METCREDMANCOLLECTIONGROUPENTITY] AS SELECT T1.COLLECTIONGROUPID AS COLLECTIONGROUPID, T1.DESCRIPTION AS DESCRIPTION, T1.RECID AS CREDMANCOLLECTIONGROUPTABLERECID, T1.DATAAREAID AS CREDMANCOLLECTIONGROUPTABLEDATAAREAID, T1.RECVERSION AS RECVERSION, T1.PARTITION AS PARTITION, T1.RECID AS RECID FROM CREDMANCOLLECTIONGROUPTABLE T1
You can use this documentation to get familiar with JSON handling in .NET 6.

JSON FIle not updating - getting "Cannot perform runtime binding on a null reference" error

Using C#, I am trying to change values in a JSON file however the values are not changing.
Below is the JSON - I intend on changing.
{
"client": {
"name": "ClientName",
"pageTitle": "PageTitle",
"serverId": 234
},
"connection": {
"router": {
"webSocketURL": "wss://pbnasdadasdasd",
"signalRUrl": "https://pbncrasdasdasdasd",
"endPoint": "https://pbncasdasdadasd",
"type": "BabelFish",
"protocol": "WebClientGameplayProtocol.WebClientGameplayProtocolDefinition",
"transport": [
"webSockets"
]
}
}
}
This is what my C# code looks like in the method.
string json = File.ReadAllText(Jsonfile);
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
jsonObj["client"]["serverId"] = "7001";
jsonObj["client"]["connection"]["router"]["webSocketURL"] = "wss://xrouter.program.eu";
jsonObj["client"]["connection"]["router"]["signalRUrl"] = "https://xrouter.program.eu/h";
jsonObj["client"]["connection"]["router"]["endPoint"] = "https://xrouter.program.eu/";
When I run my code I get a 'Cannot perform runtime binding on a null reference" error, and not sure why when there are already values in that area. ****I no longer get this error - My path was incorrect in the jsonObj****
see error below:
Thank you in advance.
The error is due to jsonObj["client"]["connection"].. where ["client"] doesnt exist for connection properties. also try using JObject.Parse
string json = File.ReadAllText(Jsonfile);
var jsonObj = JObject.Parse(json);
jsonObj["client"]["serverId"] = "7001";
jsonObj["connection"]["router"]["webSocketURL"] = "wss://xrouter.program.eu";
jsonObj["connection"]["router"]["signalRUrl"] = "https://xrouter.program.eu/h";
jsonObj["connection"]["router"]["endPoint"] = "https://xrouter.program.eu/";
Console.WriteLine(jsonObj.ToString());
Output
{
"client": {
"name": "ClientName",
"pageTitle": "PageTitle",
"serverId": "7001"
},
"connection": {
"router": {
"webSocketURL": "wss://xrouter.program.eu",
"signalRUrl": "https://xrouter.program.eu/h",
"endPoint": "https://xrouter.program.eu/",
"type": "BabelFish",
"protocol": "WebClientGameplayProtocol.WebClientGameplayProtocolDefinition",
"transport": [
"webSockets"
]
}
}
}
Based on your json hierarchy, for you to update websocket url, you need to use the below line of code to update the attribute value
jsonObj["connection"]["router"]["webSocketURL"] = "wss://xrouter.program.eu";

Capture value from the JSON array

I am trying to call an API and getting the results back in the form of JSON. I need to parse the data received and collect the specific data "key" under mapping in below mentioned JSON data from the array. I also want to get the total count of key under the mapping, so that I can recurse the array and retrieve the key.
JSON data as below,
{
"$type": "Type1",
"mapping": [
{
"value": "Value1",
"key": "Key1"
},
{
"value": "Value2",
"key": "Key2"
}
]
}
I am stuck in the code until below mentioned. Was not sure how to proceed further. Kindly suggest how can I get the value
using (var webResponse = (HttpWebResponse)webrequest.GetResponse())
{
using (var sr = new StreamReader(webResponse.GetResponseStream()))
{
text = sr.ReadToEnd();
dynamic jsonObject = JsonConvert.DeserializeObject(text);
//Need suggestion how can I retrieve the specific
}
}
Here is a quick Console app that does what you are trying to do. The trick is to traverse the dynamic object until you find what you want. But cast everything as dynamic as you go.
class Program
{
static void Main(string[] args)
{
var text = "{ \"$type\": \"Type1\",\"mapping\": [ { \"value\": \"Value1\", \"key\": \"Key1\" }, { \"value\": \"Value2\", \"key\": \"Key2\" } ] }";
dynamic result = JsonConvert.DeserializeObject(text);
dynamic mapping = result.mapping;
foreach(dynamic item in mapping as IEnumerable<dynamic>)
{
Console.WriteLine("{0}: {1}", (string)item.value, (string)item.key);
}
var done = Console.ReadLine();
}
}

How to create default json object from json schema in c#

I can not google that thing on json.net api reference or anywhere.
I want to create object from json schema with default values filled in.
Basically some thing like this:
var JsonSchema=JsonSchema.ReadSchemaFromSomeWhere();
dynamic DefaultObject= JsonSchema.GetDefaultObject();
Example you might see in json-schema-defaults package.
Example
var JsonSchema=JsonSchema.ReadSchemaFromString("
{
"title": "Album Options",
"type": "object",
"properties": {
"sort": {
"type": "string",
"default": "id"
},
"per_page": {
"default": 30,
"type": "integer"
}
}");
dynamic DefaultObject= JsonSchema.GetDefaultObject();
//DefaultObject dump is
{
sort: 'id',
per_page: 30
}
UPDATE
I want lib or api in json.net to create object with default values from any given valid json schema during runtime.
Well a simple case might be this
[Test]
public void Test()
{
dynamic ob = new JsonObject();
ob["test"] = 3;
Assert.That(ob.test, Is.EqualTo(3));
}
I used the RestSharp library that provides a good dynamic implementation that allows indexing ["test"];
So then - what You're left to do is read the properties from the schema and assign values (of course this will work only for simple plain case`s, but might be a start
dynamic ob = new JsonObject();
foreach (var prop in JsonSchema.Properties)
{
if (prop.Default != null)
ob[prop.Name] = prop.Default
}

Reading a json file and change it with JSON.NET

JSON is really new to me. How can i use JSON.NET to add a key value pair into a already created json file?
It looks like this:
{
"data": {
"subData1": {
"key1":"value1",
"key2":"value2",
"key3":"value3"
},
"subdata2": {
"key4":"value4",
"key5":"value5",
"key6":"value6"
}
}
"key7":"value7",
"key8":"value8"
}
Say for an example that i want to change it to the following:
{
"data": {
"subData1": {
"key1":"value1",
"key2":"value2",
"key3":"value3"
},
"subdata2": {
"key4":"value4",
"key5":"value5",
"key6":"value6"
},
"newSubData": {
"myKey1":"myVal1",
"myKey2":"myVal2",
"myKey3":"myVal3"
}
}
"key7":"anotherValChangeByMe",
"key8":"value8"
}
Do i need to read the whole JSON file into a dynamic, and then change / add the things i need somehow ?
You can parse the JSON into a JObject, manipulate it via the LINQ-to-JSON API, then get the updated JSON string from the JObject.
For example:
string json = #"
{
""data"": {
""subData1"": {
""key1"": ""value1"",
""key2"": ""value2"",
""key3"": ""value3""
},
""subdata2"": {
""key4"": ""value4"",
""key5"": ""value5"",
""key6"": ""value6""
}
},
""key7"": ""value7"",
""key8"": ""value8""
}";
JObject root = JObject.Parse(json);
JObject data = (JObject)root["data"];
JObject newSubData = new JObject();
newSubData.Add("myKey1", "myValue1");
newSubData.Add("myKey2", "myValue2");
newSubData.Add("myKey3", "myValue3");
data.Add("newSubData", newSubData);
root["key7"] = "anotherValChangeByMe";
Console.WriteLine(root.ToString());
Output:
{
"data": {
"subData1": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"subdata2": {
"key4": "value4",
"key5": "value5",
"key6": "value6"
},
"newSubData": {
"myKey1": "myValue1",
"myKey2": "myValue2",
"myKey3": "myValue3"
}
},
"key7": "anotherValChangeByMe",
"key8": "value8"
}
JSON is ultimately just a string. If you are working on the server side, then unless you want to try to parse out the JSON yourself, the easiest way is to use JSON.NET to deserialize it back into it's native object model. Of course, you can also do this on the client side with JSON.parse(), and add the value there, too.

Categories