How to read parse JSON String in C# [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to read a JSON string in C# (in fact, it is much longer, but just to show the structure...) This is the string that I receive.
42["cti-agentes","{
\"6139\":{
\"id_agents_interface\":\"453\",
\"agent\":\"6139\",
\"interface\":\"contact1\",
\"logintime\":\"2019-11-26 15:08:46\",
\"pausetime\":\"2019-12-31 13:28:36\",
\"paused\":\"si\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact1\",
\"textoterminal\":\"contact1\"
},
\"6197\":{
\"id_agents_interface\":\"5743\",
\"agent\":\"6197\",
\"interface\":\"contact1\",
\"logintime\":\"2020-01-16 10:16:17\",
\"pausetime\":null,
\"paused\":\"no\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact2\",
\"textoterminal\":\"contact2\"
}
}"]
The String is supposed to be an array of 'agents'. 6139 is one agent, with all its properties, and 6197 is another agent. In this example there are only two agents, but in the real string there are many of them.
I am not very familiar with the JSON format, but I tried to validate it in this web https://jsonformatter.curiousconcept.com/ and I can't make it work, so maybe I have to "clean" the string a little bit before parsing it? Hope you can help.
The aplication should be able to read the JSON string and parse it to a .NET object, I tried the JsonConvert.DeserializeObject() and JArray.Parse() functions but neither of them have worked for me.
Any help?

The first part seems to be an int, you have multiple way to remove it:
var withoutNumberPrefix = new string(input.SkipWhile(c=> Char.IsDigit(c)).ToArray());
var fixedSize = input.Substring(2, input.Length - 2);
var always42 = input.TrimStart(new[] { '4', '2' });
Once you have done that you have a List<string>, where the first value is the type and the second the "array" of that type.
var listResults = JsonConvert.DeserializeObject<string[]>(fixedSize);
You can deserialize the second part:
var result = JsonConvert.DeserializeObject<Dictionary<int,CtiAgentes>>(listResults[1]);
Into the matching type, created with a simple copy past using those tool
How to auto-generate a C# class file from a JSON string
:
public partial class CtiAgentes
{
[JsonProperty("id_agents_interface")]
public int IdAgentsInterface { get; set; }
[JsonProperty("agent")]
public int Agent { get; set; }
[JsonProperty("interface")]
public string Interface { get; set; }
[JsonProperty("logintime")]
public DateTimeOffset Logintime { get; set; }
[JsonProperty("pausetime")]
public DateTimeOffset? Pausetime { get; set; }
[JsonProperty("paused")]
public string Paused { get; set; }
[JsonProperty("id_pausa")]
public object IdPausa { get; set; }
[JsonProperty("invalid")]
public string Invalid { get; set; }
[JsonProperty("invalidtime")]
public object Invalidtime { get; set; }
[JsonProperty("fullcontact")]
public string Fullcontact { get; set; }
[JsonProperty("textoterminal")]
public string Textoterminal { get; set; }
}
In this Live demo, you will notice that there is no string manipulation except "remove the 42". Not backslash not quote were modify. It's a json hardcoded in a string Store Hardcoded JSON string to variable
Nota bene:
I used DateTimeOffset for Pausetime and Logintime, because there where no timezone in that input. You can use Datetime but it will be nice to know if it's gmt or localized data.
For all the null value I choosed object. because I don't know the type. And that will go boom sooner or later with data. One can assume that id is a int and invalid time a DateTimeOffSet, but I can't make that decision.

There are multiple issues with your text. I will try to elabroate on them in the following parts...
42 prepended to the string
Quite obvious to all of us - this just should not be there
Your json object is a list
Since your json object starts with [ it's actually a string list, that has to be separated by ,, e.g. ["a", "b", "c"], which is probably the reason for the next point...
Your json value objects are strings
First of all the following is kind of a mixture of a string list and a json object
"cti-agentes","{
\"6139\":{
\"id_agents_interface\":\"453\",
\"agent\":\"6139\",
\"interface\":\"contact1\",
\"logintime\":\"2019-11-26 15:08:46\",
\"pausetime\":\"2019-12-31 13:28:36\",
\"paused\":\"si\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact1\",
\"textoterminal\":\"contact1\"
},
But also if you wanted to have json objects, you may not have surrounding "'s around your objects.
symbol because it makes it a string instead of a json object, e.g.
"employee_1": { "name": "dominik" } instead of
"employee_1": "{ "name": "dominik" }" like it is in your example.
Conclusion
The system providing you a "json" does not provide a json and instead some string that is kind of similar to a json. Why? I don't know - probably "42" lol :)
The best advice is probably to talk to the guy who made the api and fix it
What can I do now?
Maybe you can try to extract the value for cti-agentes, since the following is actually a valid json you should be able to parse.
{
\"6139\":{
\"id_agents_interface\":\"453\",
\"agent\":\"6139\",
\"interface\":\"contact1\",
\"logintime\":\"2019-11-26 15:08:46\",
\"pausetime\":\"2019-12-31 13:28:36\",
\"paused\":\"si\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact1\",
\"textoterminal\":\"contact1\"
},
\"6197\":{
\"id_agents_interface\":\"5743\",
\"agent\":\"6197\",
\"interface\":\"contact1\",
\"logintime\":\"2020-01-16 10:16:17\",
\"pausetime\":null,
\"paused\":\"no\",
\"id_pausa\":null,
\"invalid\":\"no\",
\"invalidtime\":null,
\"fullcontact\":\"contact2\",
\"textoterminal\":\"contact2\"
}
}

Related

Need help deserializing C# / .NET 6 into seperate objects

I am attempting to use JsonSerializer.Deserialize() from System.Text.JSON in .NET 6.
I have no control over the format of the JSON.
I have used it successfully in the past but now the data I need to consume is more complicated (but not VERY complicated). I am assuming that I am simply describing my data incorrectly.
I have tried several things.... but the description below is the only way so far that I could consume the data at all.
I think my biggest problem is that I am trying to use the wiz-bang "Paste Special -> Paste JSON as Classes" without really understanding how to form my classes for serialization/deserialization.
Here is a simple example of the JSON I am trying to consume:
[
{
"version": "1.0b",
"sub_version": "x.y.barf"
},
{
"somestring": "I am a string",
"isCool": false,
"a_cool_array": [
"bob",
"jill",
"pete"
]
}
]
If I use the whiz-bang "Paste Special" tool, I get the following generated for me.
public class Rootobject
{
public Class1[] Property1 { get; set; }
}
public class Class1
{
public string version { get; set; }//<-- I need these to remain in their own object
public string sub_version { get; set; }//<-- I need these to remain in their own object
public string somestring { get; set; }
public bool isCool { get; set; }
public string[] a_cool_array { get; set; }
}
Here is the problem that I have.
The whiz-bang tool put my first object (with one version strings) and second (more complicated) object into the same object.
If I use a call like this:
var deserializedJSON = JsonSerializer.Deserialize<List<Class1>>(myJSONTextHere);
I end up with two objects in the list.
The first one has the versions filled out, the second one only has the other fields filled out.
This all makes sense to me but I don't know how to get around the problem.
I need these objects to model the JSON and I need them to save back in the same format when I re-serailize the modified classes elsewhere. This isn't my exact problem as I have simplified it for the question.
I have found one way around this problem.
It is ugly but seems to work. I hate that my code has to know about the data it is manipulating.
I used the actual JSON DOM to split the two disparate classes into individual JSON objects, then used the class de-serializer to load the individual objects into their given types.
In the following example, I am not checking anything.. I happen to know the order of the objects. I could check the raw JSON to make sure it was what I was looking for. In this case, I don't need to.
So, instead of taking the class structure as pasted by the super spiffy "Paste Classes from JSON" thingamajigger.. I split the classes myself.
Like this:
public class VersionClass
{
public string version { get; set; }
public string sub_version { get; set; }
}
public class DataClass
{
public string somestring { get; set; }
public bool isCool { get; set; }
public string[] a_cool_array { get; set; }
}
Then, I can load the JSON into the objects I need like this:
using var jsonDoc = JsonDocument.Parse(jsonText);
var versionClass = jsonDoc.RootElement[0].Deserialize<VersionClass>();
var dataClass = jsonDoc.RootElement[1].Deserialize<DataClass>();
I hope this helps someone having the same problem.
Your json needs to look like this:
{
"class1": [
//more json
],
"class2": [
//more json
]
}
Then you will have:
public class RootObject
{
// class1 and 2 in here
}
public class Class1
{
}
public class Class2
{
}

C# Newtonsoft JSON Very simple just not sure on name of thing i need

I have read a JSON document into a hashtable and started for each loop through the Dinnersets inside of it.
I have stored the current DinnerSet in my Helper class and now I just need to use a string named CurrentMeal which simply contains a mealname and use it something like this:
String MealID = MyHelper.DinnerSet.Value.Meals.CurrentMeal.MealID
My problem is I don't know how to substitute the String CurrentMeal into this and have the whole thing expanded to return me the mealID, If I do this manually:
String MealID = MyHelper.DinnerSet.Value.Meals.Pasta.MealID
I get back the correct MealID, I am sure it is very simple I just don't know what I should be googling to get onto the right track with this
Any help greatly appreciated
EDIT: JSON Structure example:
"DinnerSet001":
"Version": "0.1",
"Enabled" : true,
"Description": "These are delicious meals for one",
"Notes": "May contain Gluten or Nuts",
"Meals": {
"Pasta": {
"MealID": "MID001",
"Description": "Basic Pasta dish in a tomato and basil sauce",
"Type": "Vegetarian"
},
The way I am reading this JSON into an object is:
dynamic DinnerSetsHash = JsonConvert.DeserializeObject<Dictionary<String, dynamic>>(jsonContent);
I then start reading the Dinnersets inside the JSON using:
foreach (var DinnerSet in DinnerSetsHash) {
I get CurrentMeal from elsewhere but i know it contains the mealnames i need such as "Pasta" and i am then hoping i should then be able to substitute it and get the MealID i need
String MealID = MyHelper.DinnerSet.Value.Meals.CurrentMeal.MealID
Regards
K.
Based on the information you've given, I think what you're looking for is the square bracket syntax, also called "indexer syntax". For example:
string CurrentMeal = "Pasta";
...
string MealID = DinnerSet.Value.Meals[CurrentMeal].MealID;
Fiddle: https://dotnetfiddle.net/bEqNFN
I agree with #dbc's comment that you would probably be better off using a strongly typed model rather than dynamic so that you get the benefits of Intellisense and compile-time type checking.
The following model should work based on the JSON you've given:
public class DinnerSet
{
public string Version { get; set; }
public bool Enabled { get; set; }
public string Description { get; set; }
public string Notes { get; set; }
public Dictionary<string, Meal> Meals { get; set; }
}
public class Meal
{
public string MealID { get; set; }
public string Description { get; set; }
public string Type { get; set; }
}
You can then deserialize into a Dictionary<string, DinnerSet> (instead of Dictionary<string, dynamic>) and your code should still work with only minimal changes.
Fiddle: https://dotnetfiddle.net/D0T98K
thank you for the input,
I was thinking this over last night and i think the question i needed to ask all along was how do i deal with a JSON file that is dynamic (as mine is), it could have any number of Dinnersets and they can contain any number of meals.
I did originally go down the strongly typed route using the paste special -> paste JSON as classes in visual studio but that didn't work for me for reasons i forget now.
I will do some testing with "indexer Syntax" thank you for the name of it! it has been driving me crazy :)
I also thought of a another way to represent what i am trying to do, I know for example in PowerShell I could have done this:
MealID = (DinnerSet.Value.Meals$(CurrentMeal)`.MealID)
and that would expand the entire right hand side and give me the value i am looking for. If there is an equivalent in C# that would also solve this for me.
EDIT: yes the indexer syntax works as the $() does in PowerShell, thanks :)
Other than that i will test with the indexer syntax and Mark your reply as the answer for now, this gives me plenty to play around with, thank you all!

Modeling JSON message [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I'm using a web service with this request format:
{
"type":"LogonReq",
"id":"b43b301c-5216-4254-b3fc-cc863d4d6652",
"date":"Wed, 16 Aug 2017 17:35:34 UTC",
"parameters":[
{
"userName":"user",
"password":"password"
}
]
}
Even though every message in the API requires only 1 set of parameters, the API still requires "parameters" to be an array.
Is it better practice to have the caller create the list or to create the list in the MessageBase constructor, or something altogether different ?
Which way would satisfy an OOP purist code reviewer?
public class MessageBase<T>
{
public MessageBase() { this.parameters = new List<T>(); }
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
};
logon.parameters.Add(new LogonMessage() { userName = "user", password = "password" });
or
public class MessageBase<T>
{
public string type { get; set; }
public string id { get; set; }
public string date { get; set; }
public List<T> parameters { get; set; }
}
public class LogonMessage{
public string userName { get; set; }
public string password { get; set; }
}
var logon = new MessageBase<LogonMessage>()
{
date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss UTC"),
id = Guid.NewGuid().ToString(),
type = "LogonReq",
parameters = new List<LogonMessage>() { new LogonMessage() { userName = "user", password = "password" } }
};
You will probably find many interesting opinions and answers to this. I can only give you mine based on my experience.
I myself would probably initialize the list within the constructor
However, since you are trying to get a good idea around the phylosophy of coding, here are some things to consider :
1) Does the MessageBase object make sense or is it useful with a NULL list? Is there any scenario where I want this list as null?
2) Actually, I would expect an OOP purist to say that you should not expose the "parameters" as a List. By exposing the object as a property, someone can do this:
login.parameters.Add()
Or this
logon.parameters = anotherListOfMine
In a way it does break encapsulation. You could make the list property read only (ie, with a protected/private setter) but "clients" of this class will still be able to access all properties and methods of the List and modify/handle them.
Now, you have to expose this in some way as you will be serializing/deserializing into JSON, so that poses a problem! Maybe you can have a private/protected List field and expose the values through a readonly property that exposes an IEnumerable and behind the scenes, you are doing:
get { return myPrivateList.ToArray(); }
3) But again, do you really win that much? Your next question should be "Who is my client?" If you are exposing this class to other developers, or is part of a framework, you might want to apply something like my point number 2, and limit the exposure. If this is internal to your application and your team maybe you should be pragmatic and simply expose the List as you are doing right now.
4) Alternatively, while still making it open, you could instead have a property of type IEnumerable so you can pass in any type.
5) Another option is to expose your list because you need to serialize it, but make it readonly. Have instead different methods, or non-serializable properties, of username and password. If these parameters are always the same that is. I am thinking this might not be your case.
I think I could go on and on this. I will stop here before you hit the downvote button :).

C# parse string into object [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
For the following text:
Item 1:
student-pay
history 320.00
math 500.10 extra
Item 2:
history 220.00
math 200.10
I would like to parse this text into an Item class. Is there a more efficient way to do this?
I have the following:
var result = input.Split(
new[] { "item", "Item" },
StringSplitOptions.RemoveEmptyEntries);
foreach (string item in result)
{
var lineItems = item.Split(
new[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries);
foreach (var lineItem in lineItems.Skip(1)) // remove ":"
{
// split line again
// check if numeric
}
}
public class Course
{
public bool StudentPay { get; set; }
public ICollection<CourseItem> JobItems { get; set; }
}
public class CourseItem
{
public string Name { get; set; }
public decimal Cost { get; set; }
public bool Extra { get; set; }
}
I want to end up with List<Items>
Given that data format your stuck with having to hand code a one off solution.
A much better approach is to use a json format. Get Newtonsoft.json. It's a one liner to serialize it and a one liner to deserializer. Add another line for File.Write and File.Read and away you go.
Use JsonConvert.Serialize and JsonConvert.Deserialize, will work most classes (unlike xmlserializer).
Json is probably a better solution but it require having the control of the input string being formatted to json format.
If you have to use your existing string as input, I suggest you to use RegEx to parse each line for the object creation. Regex is the old-fashion way to tackle your problem.

Validating and Correcting JSON data during or after deserialization

I have been agonizing over this problem for a few days now and have no hope left. I'm still in the early stages of learning C#, so excuse me if my explanations or understanding are lacking.
My scenario is that I have a need to access an API and download the data as JSON then deserialize it into a class. At the moment, things work as they should, however every variable is defined as String which means I need to convert and manipulate data that should be int/double on the fly constantly as the API can give "N/A" for these data. The impression I get is relying on everything being string is bad practice.
So how should I implement it? I need to be able to store the data as the correct type while keeping in mind that it could be wrong.
Example of properties with wrong type
public string Title { get; set; }
public string Year { get; set; } // Wanted int. Often has an end year "2010-2014"
public string Metascore { get; set; } // Wanted double. Could be "N/A"
The only way I can imagine solving this is by having two classes: the first one being the original string-only class, then having the second being an almost identical class with the desired properties that uses the data from the original then converts it.
My problem with that is that the class already has a few dozen properties, so duplicating it seems nearly as wasteful as the original problem. Regardless, I would like to know an alternative for future use anyway.
EDIT:
Found a similar question here, though unfortunately it didn't help.
you can deserialize the json to JObject and than load it your self
public class RootObject
{
public RootObject(JObject obj)
{
Title = obj["Title"].ToString();
var year = obj["year"].ToString();
Year = year == "N/A" ? 0 : int.Parse(year);
var metascore = obj["Metascore"].ToString();
Metascore = metascore == "N/A" ? 0 : int.Parse(metascore);
}
public string Title { get; set; }
public int Year { get; set; }
public double Metascore { get; set; }
}
static void Main(string[] args)
{
string json = "{\"Title\":\"test\",\"year\":\"2012\",\"Metascore\":\"N/A\"}";
RootObject root = new RootObject(JObject.Parse(json));
}

Categories

Resources