I need to be able to get data from JSON using JSON.NET.
{
"labels": {
"start" : {
"action" : "ASK",
"message" : "What do you want to do, {name}?",
"responses" : {
"kill" : "GOTO label3"
}
},
"label3" : {
"action" : "END",
"message" : "Thanks for playing."
}
}
}
This is my C# code: dynamic json = JsonConvert.DeserializeObject(sourcejson);
This puts the JSON into an object that I can access like this, or similar:
Console.WriteLine(json.labels.start.responses.kill);However, I need to specify which key to retrieve based on a string, for example, retrieving "kill" based on a C# string with the contents of "kill". If I had another response in responses, I could just change the C# string to the name of the specified key and it would retrieve it. How exactly could I accomplish this?
My preference would be to deserialize into a JObject.
For example: JsonConvert.DeserializeObject<JObject>(sourceJson);
Then, you can reference the keys using standard C# indexers.
var jObj = JsonConvert.DerserializeObject<JObject>(sourceJson);
var kill = jObj["labels"]["start"]["responses"]["kill"]?.ToString();
However, make sure that you have the appropriate null checks in various places as it isn't "type-safe" code.
If you want to continue using a dynamic object you could just replace your print statement with json.labels.start.responses["kill"] as shown below;
[Test]
public void Test()
{
var sourcejson = #"{
""labels"": {
""start"" : {
""action"" : ""ASK"",
""message"" : ""What do you want to do, {name}?"",
""responses"" : {
""kill"" : ""GOTO label3""
}
},
""label3"" : {
""action"" : ""END"",
""message"" : ""Thanks for playing.""
}
}
}";
dynamic json = JsonConvert.DeserializeObject(sourcejson);
Console.WriteLine(json.labels.start.responses["kill"]);
}
Your serialized object will have a Dictionary<string, object> of all attributes and you can access the values by their keys.
Related
I have a Json and I want to get it in my c# object.
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
_ = JsonConvert.DeserializeObject<object>(json);
Here, I get the Json in the format of:
{{
"pipeline" : {
"url" : "url1",
"idP" : 1
},
"id": 1234,
"name" : "test1",
"state" : "inprogress",
"date" : "date"
}}
Now, from this JSON, I just want the id and idP.
How can I do that? Should I create a class with all the properties?
Can I please get a sample code?
If you just want id and idP, you don't need to create the classes and deserialize json. You can just parse it
var jsonParsed = JObject.Parse(json);
var id = (Int32)jsonParsed["id"]; //1234
var idP = (Int32) jsonParsed["pipeline"]["idP"]; //1
but you have to fix your json, by removing extra pair {}. You can make it manually if it is a typo. But if it is a bug, you can use this code, before parsing
json=json.Substring(1,json.Length-2);
or for example you can create one class
public class Pipeline
{
public string url { get; set; }
public int idP { get; set; }
}
and deserialize only one part of json
Pipeline pipeline = jsonParsed["pipeline"].ToObject<Pipeline>();
Is there another way to deserialize the response content of an api call into a generic object in .Net without having to create a model representing the json object? In other words, is there or does .Net provide a generic object or model that i can use to deserialize the response into. The reason being is because every api call response is not the same which means i have to create a new model for every api call. And i have about 20 different endpoints that return different responses, which means i would have to create 20 models representing the response.
My recommendation would be to create request and response models for this, even though it feels like extra work. This is because you'll need to eventually pass the parameters to functions in your business layer anyway, and you'll want to take advantage of the type safety without doing a bunch of Int32.TryParse's, which at that point, you're creating variables and doing extra work anyway. Actually, you're not going to be able to outrun the type safety the language not only provides, but generally requires. What I've done, is just copy/paste my DTO or EDMX table model into the new class, then decorate it. Pretty fast.
You may be looking for dynamic object which is late bound with unknown compile time properties.
A handy implementation of this is the JObject available with Newtonsoft.Json package and it offers similar functionality to the typeless elements of Javascript in that the properties can be of any type, with any nesting, etc. as long as it was parsed from well formed Json.
Usage is super simple, but watch out for null values, etc as default behavior for dynamic (aka ExpandoObject under the hood) is to throw exceptions for properties (aka Keys) not found...
public static void Run()
{
string apiJsonResponse = #"{
Name: 'Luke Skywalker',
Title: 'Jedi',
Skills : [
'Lightsaber',
'The Force'
]
}";
dynamic json = JObject.Parse(apiJsonResponse);
Console.WriteLine($"Name: {json.Name}");
Console.WriteLine($"Title: {json.Name}");
Console.WriteLine($"Skills: {String.Join(", ", json.Skills)}");
}
The result will be the Json dynamically parsed and rendered without any strongly typed model:
You can use generic method to have list of JObject. Based on your need you can extract model from jobject.
private static async Task<List<JObject>> CallApi(Uri uri, HttpContent data = null, string headerKey = null, string headerKeyVal = null)
{
string res = string.Empty;
try
{
var handler = new HttpClientHandler
{
//UseDefaultCredentials = true,
};
using var client = new HttpClient(handler);
if (!string.IsNullOrWhiteSpace(headerKey))
client.DefaultRequestHeaders.Add(headerKey, headerKeyVal);
var post = await client.GetAsync(uri);
//var post = await client.PostAsync(uri);
if (post.StatusCode != HttpStatusCode.InternalServerError)
{
res = await post.Content.ReadAsStringAsync();
}
return JsonConvert.DeserializeObject<List<JObject>>(res);
}
catch (Exception ex)
{
throw ex;
}
}
in .Net 3.1 after version, can use using System.Text.Json
api response data
{
"Status" : "0"
"Data" : {
"FirstName" : "firstName",
"LastName" : "lastName"
}
}
Response Model
public class ResponseModel
{
public string Status { get; set; }
public JsonElement Data { get; set; }
}
Deserialize
public void Deserialize()
{
var jsonString = "{ \"Status\": \"0\", \"Data\": { \"FirstName\": \"firstName\", \"LastName\" : \"last_name\"} }";
var response = JsonSerializer.Deserialize<ResponseModel>(jsonString);
//get first_name
var firstName = response.Data.GetProperty("FirstName").GetString();
Console.WriteLine(firstName);
}
I am using MongoDb with C# in a WebApi app. My data does not lend well to mapped data types due to the dynamic nature of the document stored. For example, here is an example of some data. Note the Data section with values that can either be arrays or a single string (Technician):
{
"_id" : "5a59129d16d5c42f7444b83d",
"CreatedDate" : "2018-01-09T20:30:19.455Z",
"Data" : {
"AlcoholTest" : [
{
"Technician" : [
"STT",
"BAT"
],
"TestReason" : "not well"
}
]
}
}
When I attempt to return the data like above, I get this instead:
{
"_id": {
"$oid": "5a59129d16d5c42f7444b83d"
},
"CreatedDate": {
"$date": 1515529819455
},
"Data": {
"AlcoholTest": [
{
"Technician": [
"STT",
"BAT"
],
"TestReason": "drunk"
}
]
}
}
Here is the code I'm using:
public object FindById(string id)
{
var filter = new BsonDocument { { "_id", ObjectId.Parse(id) } };
var result = _collection2.Find(filter);
var note = result.Any() ? result.First() : null;
var json = note.ToJson(new JsonWriterSettings{OutputMode = JsonOutputMode.Strict});
return JObject.Parse(json);
}
I can't just return the note object since Newtonsoft does not know how to convert those $data and $oid into valid types and returns a parsing error.
When I attempted to use MongoDb mapping classes in .NET, this is what my class looked like (I'm not including the BsonClassMap.RegisterClassMap stuff for simplicity):
public class Note
{
public string Id { get; set; }
public DateTime? CreatedDate { get; set; }
public IDictionary<string, IList<IDictionary<string, object>>> Data { get; set; }
}
When I tried this code, the Newtonsoft did not know how to handle the case where the object in IList<IDictionary<string, object>> could be an array or string and saved some rather nasty JArray and JObject data instead.
So here are my questions:
Is there a way to make the above C# code return identical JSON as what is represented in the Mongo database (or what the UI is sending and expecting to get back)?
Or is there a way to map my Data document using .NET types that would allow me to use MongoDb mapping classes that accepts either string values, arrays, or both?
I ended up using a different approach for save vs get. For saving, I converted a generic object to BsonDocument, and saved it as it. This resulted in the data format I was expecting (first data format my above question).
I used a strongly-typed collection to get data from the MongoDB so I could avoid the second data format from my question above. To get the data returned in the correct format, I changed this property from
public IDictionary<string, IList<IDictionary<string, IList<string>>>> Data { get; set; }
to
public IDictionary<string, object> Data { get; set; }
This gave me the correctly formatted data I needed. Having two MongoDb collections for getting vs saving was not ideal, but it eliminated my original hack to parse the dictionary BsonDocument into my strongly-typed POCO.
I have the following JSON when user clicks save
tasks : {
updated : [
{ Id : 123, SomeField1 : 'new value', SomeField2 : 'new value', SomeField3 : 'new value' },
{ Id : 125, SomeField2 : 'new value' },
{ Id : 127, SomeField1 : 'new value', SomeField4 : 'new value' },
{ Id : 129, SomeField2 : 'new value', SomeField3 : 'new value' },
{ ................ }
],
removed : [
{ Id : 345 },
{ Id : 847 }
]
}
on the MVC server side (C#), I have a ViewModel and .NET deserializes this back to my viewmodel object.
in this example, This object has Id, SomeField1, SomeField2, SomeField3, SomeField4.
The problem I am having is that the client only sends the fields which were actually updated, so If the user never updated SomeField3 it wont be in the json and .NET for that array object will have a null as SomeeField3 ...
so i cant get record, update all the fields to what the viewmodel is and then call an update as it will set SomeField3 to null , which is not correct - there could be data in that field which the user just didn't touch in this case .. (in another case they may have deleted their text, which then the update would be valid..
I am not sure what is the best way to tackle this problem.
Looking forward to your suggestions.
I suggest you to post updated string in API action, then you can get your solution as :
Create dynamic property mapping function :
public static class DynamicToStatic
{
public static T ToStatic<T>(object source, T destination)
{
var entity = destination;
//source implements dictionary
var properties = source as IDictionary<string, object>;
if (properties == null)
return entity;
foreach (var entry in properties)
{
var propertyInfo = entity.GetType().GetProperty(entry.Key);
if (propertyInfo != null && entry.Value != null)//Check property and its values exist or not ,change only when source contains value
propertyInfo.SetValue(entity, entry.Value, null);
}
return entity;
}
}
Convert your request json to dynamic object and then map dynamic object to Your static class type model, Class type model initialized from your db record or any source as per your requirement.
//updatedJsonObjectString bound from request post data(JSONSTRINGIFY of post data)
dynamic source = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(updatedJsonObjectString);
Class1 model = new Class1();//mapped/filled by data call
var retUser = DynamicToStatic.ToStatic<Class1>(source, model);
if you are using Newton Json for Deserializing.
Newton Json DeserializeObject method has an overload which takes json string and JsonSerializerSettings as parameters. JsonSerializerSettings has NullValueHandling and MissingMemberHandling properties.
MissingMemberHandling: Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled
during deserialization.
NullValueHandling: Gets or sets how null values are handled during serialization and deserialization
I would like to know if there is a way to get a specific directory structure and parse it to json so I can create a client-side treeview schema using a jquery plugin. thanks in advance
Using JSON.NET:
JToken GetDirectory(DirectoryInfo directory)
{
return JToken.FromObject(new
{
directory = directory.EnumerateDirectories()
.ToDictionary(x => x.Name, x => GetDirectory(x)),
file = directory.EnumerateFiles().Select(x => x.Name).ToList()
});
}
Example usage:
var json = GetDirectory(new DirectoryInfo("...some path...")).ToString();
This will give you JSON that looks something like this:
{
"directory":
{
"dirA": {
"file" : [ "file0.txt", "file1.jpg" ]
},
"emptyDir": {
}
},
"file": [ "file2.png" ]
}
In fact, there is an easy way to convert a C# object to JSON using Json.NET.
You simply create a List<> that contains the data you want and then call
var wrapper = new { TreeData= list };
string json = JsonConvert.SerializeObject(wrapper);
You can create custom classes like:
abstract class DirectoryChildItem
{
public string Name { get; set; }
}
class Directory : DirectoryChildItem
{
public List<DirectoryChildItem> Childs { get; set; }
}
class File : DirectoryChildItem
{
}
Then you should traverse your file system using static class System.IO.Directory and create items using classes above.
After traversing file system use "return Json(obj)" method in your ASP.NET MVC action