Dynamically reading .json file with multiple objects - c#

An application is providing me a .json file that contains an unknown amount of objects. On top of that, the objects content also changes quite a bit.
Here is an example of a json file:
{
"AVRunning":{
"Description":"Symantec Antivirus Service",
"Status":true
},
"CorrectOU":{
"Description":"Server in Correct OU",
"Status":true
},
"RoleAdGroups":{
"Result":true,
"Group":"Server-Admin"
},
"DefaultAdGroups":[
{
"Result":true,
"Group":"Domain Admins"
},
{
"Result":true,
"Group":"Server-Admins"
},
{
"Result":true,
"Group":"SERVERNAME-ADMINS"
}
]
}
This is just an example of a json file. It could contain many more objects, as well as an unknown amount of content within it.
My question to you all, is how do I serialize this into a JSON object in c# once I read the content in as one gigantic string?
Also, I may be overcomplicationg the process here. Once I read this in, I want to pass the data to my view. If this can't be done in c#, would it be easier to do it in Jquery? Or should it be done there in the first place? The file that I am reading in is a local file, so I can't access the data directly in jquery.
I know JSON.NET is a possible tool, but from what I have read, I am not sure how to create the objects dynamically.

You have to define data types into which you want to deserialize json string:
public class ObjectWithDescriptionAndStatus
{
public string Description;
public string Status;
}
public class ObjectWithResultAndGroup
{
public bool Result;
public string Group;
}
public class MyObject
{
public ObjectWithDescriptionAndStatus AVRunning;
public ObjectWithDescriptionAndStatus CorrectOU;
public ObjectWithResultAndGroup RoleAdGroups;
public IList<ObjectWithResultAndGroup> DefaultAdGroups;
}
This is the simplest example, with all fields marked as public and named exactly as keys in the json (they can have arbitrary names but in that case you have to decorate each field with DataMember attribute and set its Name property to the actual name of the key).
Having data types defined, deserialization is a one-liner:
MyObject myObject = Newtonsoft.Json.JsonConvert.DeserializeObject<MyObject>(json);

jQuery makes it pretty simple (just jQuery.parseJSON(<your string>);).
I imagine JSON.NET has a parse function as well, but I haven't used that library, so I couldn't say for sure!

Related

Trying to deserialize JSON object array where the objects have arrays as properties. Can I map the array elements to specific properties of a class?

I am deserializing a json file into C# objects, in this case MTG cards (json from scryfall.com). Previously I solved the problem with MSSQL; I imported the json data into the database with OPENJSON mapping each element I needed to a column with a proper name, and then created a new json file with properties that matched the class I needed in the application.
For properties like arena_id that have only one value, or for arrays that were used as strings (color_identity), it was not an issue, but for arrays such as card_faces (cards that have 2 playable sides) I had to specify which element of the array I wanted to import.
arena_id int '$.arena_id',
...
[color_identity] nvarchar(max) AS JSON,
...
name_front varchar(100) '$.card_faces[0].name',
mana_cost_front varchar(30) '$.card_faces[0].mana_cost',
name_back varchar(100) '$.card_faces[1].name',
mana_cost_back varchar(30) '$.card_faces[1].mana_cost',
From the SQL tailored file I deserialized every object accordingly, but now I'm trying to do it without SQL and with more direct influence as to what goes where.
As mentioned before, for properties that do not need to be deconstructed I know I can just pick the same property name in the class and it gets accepted easily. My problem is with array properties that I should divide into separate properties with different names.
Is it possible in C# to deserialize in a similar way?
I'm thankful for all kinds of hints and tips as I am relatively new to programming with only one year in a training course.
You just need to create a class that properly represents the expected JSON format, EG:
public class MyClass
{
public int Arena_Id { get; set; }
public CardFace[] Card_Faces { get; set; }
}
public class CardFace
{
public string Name { get; set; }
public string Mana_Cost { get; set; }
}
Then deserialize your JSON:
string json = ... // your data
MyClass x = new Newtonsoft.Json.JsonSerializer() // or whichever serializer you want
.DeSerialize<MyClass>(json)
With this deserialized instance of your class, you can then translate it to another class matching the structure you require.
I am guessing that you are simply able to at least call the JSON.
C# does have a good JSON deserialization directive.
// keep the class as close to how it will show up on the JSON
public class MTGCard
{
public string name;
public int manaCost;
...
}
// then you should be able to just
currentCard = JsonSerializer.Deserialize<MTGCard>(jsonString);
The class and the json are close enough you should be able to simply use the Array features pull the cards you need and then just deserialize it on the call based

Converting JSON data into an object

I am very new to this.Pardon me if I make any mistakes.
I have data in JSON form.Can I read this data directly and use it in C# code ?
From what I understood from reading up on the internet,I think I have to convert it into an object form to use the data.Am I right ?
If yes,Then I saw this method to convert as below :
string data = JsonConvert.DeserializeObject<string>(getmyissue());
getmyissue is the function which returns a string which has data in json format.
This gives me an exception saying
"Error reading string.Unexpected Token."
Can someone guide me where am I going wrong ?
EDIT
MyIssue.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example
{
public class MyIssue
{
public string name{get;set;}
public string description { get; set; }
public string created { get;set; }
public string updated{get;set;}
public string displayName { get; set; }
}
}
Program.cs
MyIssue obj=null;
try
{
obj = JsonConvert.DeserializeObject<MyIssue>(manager.getmyissue());
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Name: "+obj.name);
The easiest way to de-serialize Json in a C#/.NET program is to use the brilliant NewtonSoft JSON library.
There are numerous ways to do it, but I have to admit that the NS libs just get on with the task (and no I'm not a member of the team etc, just an Avid User :-) ).
To do what you want for example, if you had:
{'Name': 'A person', 'AllowAccess': true,'Areas': ['Sales','Admin']}
You would first build an object to represent it as follows:
public MyObject
{
public string Name { get; set; }
public bool AllowAccess { get; set; }
public List<string> Areas { get; set; }
}
Once you've done this, it's a simple case of just doing the following:
string jsonString = "// Your json formated string data goes here";
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(jsonString);
The properties in your object should at that point, reflect the properties in the JSON data you sent to it.
You will of course need to add the NS JSON Libs to your project, either via NuGet or Manually, which ever is easier for you, everything you need to know about that is here:
How to install JSON.NET using NuGet?
The really good thing about NS JSON however is not the ease of use, but the fact that it can also do dynamic de-serialization.
This comes in handy if you've no idea what to expect in the JSON you receive, and so don't know ahead of time how to construct an object to hold the results.
Rather than repeat what others have said however, you can find more information of doing things dynamically in this stack overflow post:
Deserializing JSON using JSon.NET with dynamic data
Update
Looking at your JSON data you have way more fields/properties in there than your trying to parse, and none of the libraries in common use (To the best of my knowledge) will pick and choose the fields to copy, you either have an object that represents them all, or not at all, the later of which I believe is the problem your facing.
I have a rather neat "JSON" plug in for chrome, than when given a chunk of JSON data formats the output for me nicely and makes it easy to read, it also helps massively when defining objects, allowing you to see the full nested structure of your data, here are a series of images showing your JSON data formatted using this plugin:
I'm not going to paste anymore images in, but that goes on for another 4 pages!!
Now, some extra information that may help you.
I know from experience (I had to write a parser in PHP for these Jira webhooks) that within the Jira control panel, you can configure your webhooks to ONLY return the information your interested in.
Right now, it looks like you've just told the system to dump everything, for every event that you've hooked too (Which looks like - all of them), it's been a while since I did any work with these, but as well as a global webhook, you also have individual webhooks, which only fire on specific events and produce JSON data that's very much smaller than what your dealing with here.
I'd therefore advise you, to take a look in your Jira control panel (Or ask your Admin/Lead Dev/etc to take a look) and seriously trim down as much of that data as you can.
Further more, if memory serves me right, you can also make various web API calls to the Jira service to get this info too, and in that case you can tell the API exactly what your interested in, meaning it will only return the fields you need.
Right now, your main problem is the sheer volume of data your trying to deal with, if you tackle that problem, you'll find the issues surrounding the code your trying to get working will be very much easier to deal with.
Update 2
Just to make it clearer what I mean by using a "dynamic" type to get at your data, you would use something like the following code:
string jsonString = "// Your json formated string data goes here";
var result = JsonConvert.DeserializeObject<dynamic>(jsonString);
The difference here is that your using the C# dynamic type rather than a strongly typed object of your own design.
"dynamic" is useful, because it's kind of like having an empty object, and then having the properties added for you, without you having to define it.
What this essentially means is that, if you pass in the following JSON:
{'Name': 'A person', 'AllowAccess': true,'Areas': ['Sales','Admin']}
You'll end up with a dynamic object that looks like:
result = dynamic
{
public string Name { get; set; }
public bool AllowAccess { get; set; }
public List<string> Areas { get; set; }
}
thus:
result.Name
will get you access to the contents of the Name field and so on.
If your JSON was then changed to become:
{'Name': 'A person', 'AllowAccess': true,'Areas': ['Sales','Admin'], 'Location': 'The World' }
Your object would magically have a property called 'Location' containing the value 'The World' which you could access using:
result.Location
In your case, this would allow you to define your concrete object EG:
public MyObject
{
public string Name { get; set; }
public string Email { get; set; }
}
and then do something like the following (Assuming that your inbound JSON had properties in called Name & Email):
string jsonString = "// Your json formated string data goes here";
var result = JsonConvert.DeserializeObject<dynamic>(jsonString);
MyObject myObject = new MyObject
{
Name = result.Name,
Email = result.Email
}
You'd then discard the dynamic object as you'd not need it anymore.
The BIG problem your going to have with this approach is maintaining your models. Manual property assignment is all fine and dandy for a small handful of properties and objects, but it soon becomes a huge maintenance nightmare as your software grows.
I'm sure it doesn't take much to imagine what kind of task you'd be facing if you had to do this for 100 different JSON requests and 50 different types of objects.
For this reason, using this approach you should really consider using some kind of mapping technology such as "AutoMapper", however for now I'm going to advise you leave that until later before you start researching it, as it'll not help you to be clear about dealing with this dynamic approach.
The JSON you get is already a string, so converting it to string doesn't make much sense. You need to create classes that reflect the structure represented by the JSON string.
For example to convert the following JSON into objects, you'd have to create a class for the users:
{"user":{"name":"asdf","teamname":"b","email":"c","players":["1","2"]}}
public class User
{
public string name { get; set; }
public string teamname { get; set; }
public string email { get; set; }
public Array players { get; set; }
}
Then you should be able to use this:
JavaScriptSerializer jss= new JavaScriptSerializer();
List<User> users = jss.Deserialize<List<User>>(jsonResponse);

Proper use of "$ref" property in JSON Pagination / Json.net

I'm trying to write a C# class for a RESTful web service which returns some items but uses JSON Pagination. I'm using JSON.net for serialization and deserialization.
I have the following code:
static void RefTest()
{
PageTest PageToTest = new PageTest();
PageToTest.next = new PageTest.PageLink();
PageToTest.next.reference = "https://www.example.com/RESTQuery/?page=1";
PageToTest.items = new List<string>();
PageToTest.items.Add("Car");
PageToTest.items.Add("Truck");
PageToTest.items.Add("Plane");
string JSON = JsonConvert.SerializeObject(PageToTest);
PageTest DeserializedPageTest = JsonConvert.DeserializeObject<PageTest>(JSON);
}
While the class looks as follows:
public class PageTest
{
public PageLink next;
public List<string> items;
public class PageLink
{
[JsonProperty("$ref")]
public string reference;
}
}
When I serialize that to a string, I get the expected result:
{
"next": {
"$ref":"https://www.example.com/RESTQuery/?page=1"
},
"items":
[
"Car",
"Truck",
"Plane"
]
}
Until now, everything works fine, it looks like json.net doesn't do anything special with the $ref property when serializing to a string.
Upon parsing of the string, however, json.net recognized the property named "$ref" as an reference to some id (which it can't find) and does NOT put it back on the deserialized object.
This is to be expected, but the web service is handing out pagination that way (With "next", "previous" and "last" attributes).
Basically, since it's impractical (I guess?) for the server to just give me all the values I will have to live with the pagination. So when I want to get all the items, I will have to deserialize the JSON response, check for additional items (indicated when there is a "next" property) and do the process again, until I have retrieved all the data I want.
Do you have any ideas on how I could handle that?
Thanks!

handling JSON response that is not the same each time

i am working with json.net to deserialize json -> C# objects.
it works great in most cases but there are times where rather than getting an array i get object.
so my class (generated using http://json2csharp.com/ and modified to add property).
where i more than 1 arrival methods (such as pick up or ship) it works fine.
public class ArrivalMethods
{
[JsonProperty(PropertyName = "ArrivalMethod")]
public List<string> ArrivalMethod { get; set; }
}
but it breaks where there only 1 arrival method in the json response from my service because i believe json.net is expecting an object like below.
public class ArrivalMethods
{
[JsonProperty(PropertyName = "ArrivalMethod")]
public string ArrivalMethod { get; set; }
}
i am new to json etc. so i am not sure what i am doing wrong. but this throws exception.
Error converting value \"Ship\" to type 'System.Collections.Generic.List`1[System.String]'.
Path 'ProductDetail.SoftHardProductDetails.Fulfillment.
ArrivalMethods.ArrivalMethod', line 1, position 113."
here is where it breaks:
"ArrivalMethods":{
"ArrivalMethod":"Ship"
},
Your JSON should contain [] where there is a list. And if I'm understanding your answer correct, the first class example is the way you want to end up? If so you need the JSON on the bottom to mark ArrivalMethod as a list, wich its not now.
"ArrivalMethods":
{
"ArrivalMethod":["Ship"]
},
To be honest i get a little confused when there is a list with no plural ending.
If you can change the response format that would be the best. It really looks like XML semantics converted to JSON...
If you can't change the response format, you can try to use JsonConverterAttribute to create custom converters for those properties.

MVC 4 ApiController not serializing System.Json.JsonObject properly

So I am new to working with MVC4 and the serialization of objects on the back end seems pretty "magical" to me so if I am doing this the wrong way please let me know.
My goal however is to build a simple rest API and return JSON out. I figured that I would use System.Json and just return JsonObject. I have simplified this down for the sake of this question but the objects are much more complicated in my real issue.
Here is my controller....
....
public class ActionsController : ApiController
{
// GET api/actions
public JsonObject Get()
{
JsonObject testObjet = new JsonObject();
testObjet.Add("Name", "Test name");
testObjet.Add("Description", "Test Description");
return testObjet;
}
....
I would expect to see:
{"Name":"Test name","Description":"Test Description"}
Instead I see:
{"Name":[],"Description":[]}
I actually seem to get better results when I return a string of the JsonObject or heck even just return the object itself with the exception it has enums and I want to return the names not the number values, which is what led me to JsonObject for customization.
Does anyone know why it is dropping off the values?
EDIT:
So because of Dan's comments below I tried just for giggles to see what the XML serializer spit out with the JSON object and I get the below exception...
"Type 'System.Json.JsonPrimitive' with data contract name 'JsonPrimitive:http://schemas.datacontract.org/2004/07/System.Json' is not expected."
So it appears that you can not serialize the System.Json.JsonObject object, because it uses a type that it does not expect.
That is shocking. Does anyone have a workaround? If not I am off to find out how to show enum names when serializing instead of values.
So the answer is apparently... You Can't!
It appears that the type JsonPrimitive is not supported to serialize objects. The answers provided below by Obi and Dan helped me to poke around a bit more and find out that the XML serializer actually throws an exception while the JSON serializer simply eats it and puts out an empty array which is what you see above.
There are any number of correct answers here.
Make your own custom serializer
Output JSON as a string
Return custom objects and then work around things like the Enum
values
I am sure there are others.
But whatever you do don't try to use System.Json as a return in the ApiController because you will get the results above.
You should not force your WebApi call to use a particular format like JSON. One of the features of WebApi is that you can specify the format as part of the request. Return an object from your Get call, and let the WebApi engine do the serialization and deserialization:
public class DataObject
{
public string Name { get; set; }
public string Description { get; set; }
}
public class ActionsController : ApiController
{
// GET api/actions
public DataObject Get()
{
var testObject = new DataObject
{
Name = "Test name",
Description = "Test Description"
};
return testObject;
}
}
You can specify the format by setting the Accept header to application/xml, application/json, etc.
The default JSON serializer has no problem serializing simple string properties like Name and Description.
I would suggest you did this instead
// GET api/actions
public object Get()
{
//New up a strongly typed object if you want to return a specific type
//and change Action return type accordingly
var testObjet = new (){
Name= "Test name",
Description= "Test Description"
};
return testObjet;
}
Dan has posted a similar answer below so let me try to address your other problem. To serialize the enum, I would suggest you hide it in a public string property which would return the string value of the enum,
public class DataObject{
public MyEnum SomeEnumValue;
public string EnumValue{
get {
//..return SomeEnumValue string value
}
}
}
You can then read the value from EnumValue which should be properly serialized as you want.

Categories

Resources