I have a complex JSON object that I'd like to pass to a MVC4 Controller route.
{
"name": "Test",
"description": "Description",
"questions": [
{
"id": "1",
"type": "1",
"text": "123",
"answers": [
{
"answer": "123",
"prerequisite": 0
},
{
"answer": "123",
"prerequisite": 0
}
],
"children": [
{
"id": "2",
"type": "2",
"text": "234",
"answers": [
{
"answer": "234",
"prerequisite": 0
},
{
"answer": "234",
"prerequisite": 0
}
],
"children": []
}
]
}
]
I have these ViewModels defined:
public class FormDataTransformContainer
{
public string name { get; set; }
public string description { get; set; }
public QuestionDataTransformContainer[] questions;
}
public class QuestionDataTransformContainer {
public int type { get; set; }
public string text { get; set; }
public AnswerDataTransformContainer[] answers { get; set; }
public QuestionDataTransformContainer[] children { get; set; }
}
public class AnswerDataTransformContainer {
public string answer { get; set; }
public int prerequisite { get; set; }
}
And this is the route I'm hitting:
[HttpPost]
public ActionResult Create(FormDataTransformContainer formData)
{
Currently, the name and description property on FormDataTransformContainer are set, but the questions array is null. I hoped that the Data Binding would figure it out, but I assume the tree nature of the data structure is a little complex for it. If I'm correct what is the best solution to this?
questions should be a property, not a field. I'd also change from arrays to IList<> (assuming your serialization library handles that well), because that's probably closer to what it should be, and lets you use a more generic interface instead of a specific implementation.
public class FormDataTransformContainer
{
public string name { get; set; }
public string description { get; set; }
public IList<QuestionDataTransformContainer> questions { get; set; }
}
public class QuestionDataTransformContainer {
public int type { get; set; }
public string text { get; set; }
public IList<AnswerDataTransformContainer> answers { get; set; }
public IList<QuestionDataTransformContainer> children { get; set; }
}
public class AnswerDataTransformContainer {
public string answer { get; set; }
public int prerequisite { get; set; }
}
I've tested this structure with Json.net (MVC4's default, I believe), and it works.
As #robert-harvey said, you should utilize libraries like JSON.NET that are already available to do the heavy lifting for you.
Pulled from the JSON.NET API docs:
If you create a string json that holds your json, you can read from it with new JsonTextReader(new StringReader(json))
I a similar problem, solved with the following code:
public class ExtendedController : Controller
{
public T TryCreateModelFromJson<T>(string requestFormKey)
{
if (!this.Request.Form.AllKeys.Contains(requestFormKey))
{
throw new ArgumentException("Request form doesn't contain provided key.");
}
return
JsonConvert.DeserializeObject<T>(
this.Request.Form[requestFormKey]);
}
}
And usage:
[HttpPost]
[ActionName("EditAjax")]
public ActionResult EditAjaxPOST()
{
try
{
var viewModel =
this.TryCreateModelFromJson<MyModel>(
"viewModel");
this.EditFromModel(viewModel);
return
this.JsonResponse(
this.T("Model updated successfuly."),
true);
}
catch (Exception ex)
{
this.Logger.Error(ex, "Error while updating model.");
return this.JsonResponse(this.T("Error"), false);
}
}
Called from JS:
function saveViewModel() {
$.post(
'#Url.Action("EditAjax")',
{
__RequestVerificationToken: '#Html.AntiForgeryTokenValueOrchard()',
viewModel: ko.mapping.toJSON(viewModel)
},
function (data) {
// response
});
}
Used additional library for deserializing/serializing JSON: http://www.nuget.org/packages/Newtonsoft.Json
Related
I have little to no experience in JSON and I am stuck with a problem. Any help is appreciated.
I want to access specifically the names' values from the additionalInformation array.
JSON Response:
{
"statusCode": 200,
"version": 1,
"jsonData": [
{
"additionalInformation": [
{
"id": "XXX94XXXX9xxXx_xxxXXXX",
"name": "xxxx xxx x xxxxxxxx"
},
{
"id": "0xXXxcXxv5PQqT$6i2zLgV",
"name": "xxx xxxxxxxx"
},
{
"id": "11Krt_our2rPCPqJ_2fKZR",
"name": "xxx xxxxxxxx xx"
},
{
"id": "2jYw4IyBP8KuozM_ej7DGf",
"name": "xxxxxxx 1"
},
{
"id": "3B8O805wL1ufabHMz1Je3v",
"name": "xxxxxxx 2"
},
{
"id": "0FVKUYZkvFaxd_OQUiyPBZ",
"name": "xxxxxxx"
},
{
"id": "3O41QFd0573QQvFco5zUUP",
"name": "Xxxxxxxxx"
}
],
"type": 0
}
],
"errorMessages": [],
"warningMessages": [],
"informationMessages": []
}
Model:
public class CFunctions
{
public int statusCode { get; set; }
public int version { get; set; }
public List<PFunctions>[] jsonData { get; set; }
public List<string> errorMessages { get; set; }
public List<string> warningMessages { get; set; }
public List<string> informationMessages { get; set; }
/*public CFunctions()
{
jsonData = new List<PFunctions>();
}*/
}
[Serializable]
public class PFunctions
{
public List<PAdditionalInfo>[] additionalInformation { get; set; }
public int type { get; set; }
/*public PFunctions()
{
additionalInformation = new List<PAdditionalInfo>();
}*/
}
[Serializable]
public class PAdditionalInfo
{
public Guid id { get; set; }
public string name { get; set; }
}
Deserialisation
var request = UnityWebRequest.Get(baseurl);
var operation = request.SendWebRequest();
var jsonResponse = request.downloadHandler.text;
List<CFunctions>[] PFunctionsList = JsonConvert.DeserializeObject<List<CFunctions>[]>(jsonResponse);
Error:
Cannot deserialize the current JSON object into type 'System.Collections.Generic.List`1[CFunctions][]' because the type requires a JSON array to deserialize correctly.
To fix this error either change the JSON to a JSON array or change the deserialized type so that it is a normal .NET type that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'statusCode', line 1, position 14.
UnityEngine.Debug:Log(Object)
What I tried
The error pertains even when I changed List<PAdditionalInfo> to List<PAdditionalInfo>[]
I am not sure how to use JsonObjectAttribute and if it is the best way.
You've declared an array of List<T> in the models, eg List<PAdditionalInfo>[]. The json represents single arrays, not nested. You can fix that by choosing one or the other (I decided to use List<> but array is valid too):
public class PFunctions
{
public List<PAdditionalInfo> additionalInformation { get; set; } // removed []
...
}
public class CFunctions
{
public int statusCode { get; set; }
public int version { get; set; }
public List<PFunctions> jsonData { get; set; } // removed []
...
}
The class you're deserializing to is incorrect. Deserialize to the correct type (which is CFunctions not List<CFunctions>[]):
CFunctions cFunctions = JsonConvert.DeserializeObject<CFunctions>(json);
the most efficient way to get an additional information is this one line code and you only need one class
List<AdditionalInformation> additionalInformation = JObject.Parse(json)
["jsonData"][0]["additionalInformation"].ToObject<List<AdditionalInformation>>();
class
public class AdditionalInformation
{
public string id { get; set; }
public string name { get; set; }
}
I have a JSON snippet here taken from HttpClient class below in a C# .NET 5 program.
Simplified JSON:
{
"Restaurants":
[
{
"Id": 138898,
"Name": "Willesborough Cafe",
"Rating": {
"Count": 76,
"Average": 5.92,
"StarRating": 5.92
},
"CuisineTypes": [
{
"Id": 92,
"IsTopCuisine": false,
"Name": "Breakfast",
"SeoName": "breakfast"
}, {
"Id": 106,
"IsTopCuisine": true,
"Name": "British",
"SeoName": "british"
}
],
"Cuisines": [
{
"Name": "Breakfast",
"SeoName": "breakfast"
}, {
"Name": "British",
"SeoName": "british"
}
]
}
]
}
Current code:
dynamic result =
await _httpClient.GetFromJsonAsync<dynamic>(url);
// dynamic result2 = JsonConvert.DeserializeObject<dynamic>(result); // slow
dynamic result2 = JObject.Parse(result); // slow
I am interested to get the info from each restaurant below from the Restaurants array:
Name
Rating
CusineType
I use dynamic as I do not need to create multiple classes based on the JSON structure & I do not need to change my class if the JSON structure changes.
I have tried JsonConvert.DeserializeObject & JObject.Parse.
However, the Visual Studio debugging stuck at either of the method for a very long period
What is the recommended method to get partial properties from a huge JSON response?
Thanks
You can make a class with named properties
class Restaurant
{
public string Name { get; set; }
public Rating Rating { get; set; }
public List<CuisineType> CuisineTypes { get; set; }
}
class Rating
{
public int Count { get; set; }
public decimal Average { get; set; }
public decimal StarRating { get; set; }
}
class CuisineType
{
public int Id { get; set; }
public bool IsTopCuisine { get; set; }
public string Name { get; set; }
public string SeoName { get; set; }
}
and deserialize json to instance of Restaurant then you have a type you need. That's it.
You need to have a class contains list of Restaurant, because you must have a property equal name with your json object
class RestaurantList { public List<Restaurant> Restaurants {get; set;} }
Now you need a code to bind section of json to object
var restaurants = JsonConvert.DeserializeObject<RestaurantList>(result);
I have the below rather simple build of classes, they represent a model, kindly note the linked classes (initialization included in appropriate instance constructors of each one):
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public DataClass()
{
part = new PartClass();
member = new MemberClass();
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
public MemberClass()
{ side = new SideClass(); }
}
public class SideClass : IMPropertyAsStringSettable
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
public SideClass()
{ }
}
My problem is rather straightforward, however, the complication is on the implementation: I am creating a class dynamically, expando, and I read a JSON which, sometimes, is equivalent one-on-one with the DataClass hierarchy, like:
{
"num": "3",
"code": "some sort of string",
"part": {
"seriesNum": "3",
"seriesCode": "sample"
},
"member": {
"versionNum": "1.5",
"side": {
"firstDetail": "aFirst",
"secondDetail": "aSecond",
"include": "true"
}
}
}
and sometimes, only a few values are equivalent (being a sub-set of DataClass is not an error, if there is an unknown tag in JSON, this is an error - like for example, find "age": "18" in JSON, because DataClass does not contain anywhere an 'age' property etc.), like for example:
{
"num": "9",
"part": {
"seriesNum": "3",
},
"member": {
"versionNum": "1.5",
"side": {
"include": "true"
}
}
}
As said, I don't care if a property - or a whole tree of properties - is missing from the JSON compared to the DataClass.
My problem is, how to read the JSON and assign properties and values in expando, while checking that both the hierarchy as well as the property name are correct.
Could you help me please with this?
I am new to converting json to csv. I have a complex json file. I am trying with following code to strongly derserialize to c# class. but nothing is working. firstly not able to deserialize and not sure the best way to write this to csv. there are around 20 entries in the json like "0", ..."19".
json data:
{
"0": [
{
"filenames": [
"a.txt",
"b.txt",
"c.txt"
]
},
{
"cluster_number": 0
},
{
"Top_Terms": [
"would",
"get",
"like"
]
}
],
"1": [
{
"filenames": [
"a.txt",
"b.txt",
"c.txt"
]
},
{
"cluster_number": 0
},
{
"Top_Terms": [
"would",
"get",
"like"
]
}
]
}
c# classes:
[DataContract(Name ="0")]
public class Zero
{
public IList<string> filenames { get; set; }
public int? cluster_number { get; set; }
public IList<string> Top_Terms { get; set; }
}
[DataContract(Name = "1")]
public class One
{
public IList<string> filenames { get; set; }
public int? cluster_number { get; set; }
public IList<string> Top_Terms { get; set; }
}
[DataContract]
public class Example
{
public IList<Zero> Zero { get; set; }
public IList<One> One { get; set; }
}
using (StreamReader r = new StreamReader("data.json"))
{
string json = r.ReadToEnd();
var result = JsonConvert.DeserializeObject<Example>(json);
}
I've checked out a few questions on StackOverflow but can't find a method that works for me.
I'm essentially trying to deserialise the following JSON into a list of my "suppressedContact" class, but I can't get it to work.
The JSON looks like this:
[
{
"suppressedContact": {
"id": 23,
"email": "nelson.redeker#example.com",
"optInType": "Unknown",
"emailType": "PlainText",
"dataFields": null,
"status": "Unsubscribed"
},
"dateRemoved": "2015-09-18T15:26:25.2612537Z",
"reason": "Unsubscribed"
},
{
"suppressedContact": {
"id": 25,
"email": "terry.mccarthy#example.com",
"optInType": "VerifiedDouble",
"emailType": "Html",
"dataFields": null,
"status": "Unsubscribed"
},
"dateRemoved": "2015-02-24T13:06:42.933Z",
"reason": "Unsubscribed"
},
]
The class I am trying to deserialise into looks like this:
public class SuppressedRoot
{
public Suppressedcontact suppressedContact { get; set; }
public DateTime dateRemoved { get; set; }
public string reason { get; set; }
}
public class Suppressedcontact
{
public int id { get; set; }
public string email { get; set; }
public string optInType { get; set; }
public string emailType { get; set; }
public object dataFields { get; set; }
public string status { get; set; }
}
I'm using this piece of code to attempt to accomplish this:
List<Suppressedcontact> unsubscribedContacts = JsonConvert.DeserializeObject<List<Suppressedcontact>>(jsonResponse);
This however does not work.
Any help in this would be appreciated, I'm trying to get to a stage where I can loop through all of the returned contacts and extract the email addresses.
Try replacing
List<Suppressedcontact> unsubscribedContacts = JsonConvert.DeserializeObject<List<Supporesscontact>>(jsonResponse);
with
List<SuppressedRoot> unsubscribedContacts = JsonConvert.DeserializeObject<List<SuppressedRoot>>(jsonResponse);