I get JSON data which root element is always data {}.
The next element however changes each time as it is an ID which is specified within the request URL. The URL is sent as a GET request and returns data about the entries associated with that specific ID.
Example:
{
"data": {
"B270233545C33F0E5d264d60d": [{
...
}]
}
The ID B270233545C33F0E5d264d60d changes each time, so I can't define a class like the following:
public partial class Data
{
[JsonProperty("B270233545C33F0E5d264d60d")]
public B270233545C33F0E5D264D60D[] B270233545C33F0E5D264D60D { get; set; }
}
I need to define it as:
public partial class Data
{
[JsonProperty("id")]
public id[] id { get; set; }
}
I tried to parse a JSON with the ID statically set to 'id' and... as expected, it was NULL after parsing.
Is there any way to map a dynamic ID to the the class property ID which is a JsonProperty?
Using JToken like #Fildor mentioned fixed it.
It is not perfect but it works.
internal partial class Data
{
[JsonExtensionData]
public IDictionary<string, JToken> Id;
}
Now my class is serialized properly and I can get all my instances:
var x = test.Data.Id.Select(n => n.Value.ToObject<id[]>()).ToList();
Related
I have the following json Object which i am sending to Web Api controller Using ajax.
var dataObject = {
LanguageId: 1,
SubTenantId: 1,
Object:{"TestApplication":{"Aplication":null}}
}
Controller function RequestObject generic class.
public IHttpActionResult ComplexObject(RequestObject<TestApplicationMain> pubRequestObject)
I am using following Class hierarchy.
public class TestApplicationMain
{
public TestApplicationMain()
{
TestApplication = new TestApplication();
}
public TestApplication TestApplication{get; set;}
}
public class TestApplication
{
public TestApplication()
{
Aplication = new List<ApplicationSearchParam>();
}
public List<ApplicationSearchParam> Aplication { get; set; }
}
public class ApplicationSearchParam
{
public ApplicationSearch ApplicationSearch { get; set; }
public string OrderBy { get; set; }
}
When i send {"TestApplication":{"Aplication":null}} json to the controller. I receive One item Aplication .
Api controller works as expected when i send {"TestApplication":{"Aplication":undefined}} OR {"TestApplication":{"Aplication":[]}}
My Question is Why Asp.net WebApi Controller add one item in nested child list when its set to null ?.
First Problem Spotted:
var dataObject = {
LanguageId: 1,
SubTenantId: 1,
Object:{"TestApplication":{"Aplication":null}}
}
Your JSON is at a level higher than TestApplicationMain
You defined LanguageId and SubTenantId but your receiving class TestApplicationMain does not handle either of the values.
You have not defined Object in TestApplicationMain
The reason your first test scenario {"TestApplication":{"Aplication":null}} works is because TestApplication is a property of TestApplicationmain
When you are automapping JSon Key-Value pairs, the name of the Key needs to match the name of the Property you wish its value to be assigned.
You test JSON should be:
var dataObject = {"TestApplication":{"Aplication":""}}
as this structure would map to:
TestApplicationMain -> TestApplication -> Aplication = ""
My Suggestions:
https://stackoverflow.com/a/31022729/659246
https://www.strathweb.com/2013/06/supporting-only-json-in-asp-net-web-api-the-right-way/
I need to receive the next JSON in .NET
"currentData":
{
"Name": {"system": "wfdss", "canWrite": true },
"DiscoveryDateTime": { "system": "wfdss", "canWrite": true },
"Code": { "system": "code", "canWrite": false },
...
}
This elements are dynamics, it doesn't have default elements, so, how can I define a class doing that following next model:
public class currentData
{
//TODO
//<Data Element Name>: {
//data element system: <STRING of system>,
//the last system to update data element canWrite: <Boolean>
//true if requesting system may edit data element (based on ADS), otherwise false. }, ...
public List<Property> property { get; set; }
}
public class Property
{
public string system { get; set; }
public string canWrite { get; set; }
}
If you need to post dynamic structured Json to controller i have a bad news for you - you can't map it automattically in MVC. MVC model binding mechanism work only with stronly typed collecions - you must know structure.
One of the options that i can suggest you if use FormCollection and manually get values from it:
[HttpPost]
public JsonResult JsonAction(FormCollection collection)
{
string CurrentDataNameSystem = collection["currentData.Name.system"];
// and so on...
return Json(null);
}
Another option is to pass you dynamic json as string and then manually desirialize it:
[HttpPost]
public JsonResult JsonAction(string json)
{
//You probably want to try desirialize it to many different types you can wrap it with try catch
Newtonsoft.Json.JsonConvert.DeserializeObject<YourObjectType>(jsonString);
return Json(null);
}
Anyway my point is - you shouldn't mess with dynamic json unless you really need it in MVC.
I suggest you to creage object type that contain all the passible fields but make it all nullable so you can pass your Json and it will be mapped with Model binding MVC mechanism but some fields will be null.
I think the type format you are getting is an Object with a Dictionary.
So i think you need to Deserialize your Data into this.
public class ContainerObject
{
public Dictionary<String,Property> currentData { get; set; }
}
In the client-side, I am using AngularJS and in the server-side I am using ASP.NET WebAPI.
I have two view models, ProductCriteriaViewModel and SimpleDisplayFieldViewModel:
public class ProductCriteriaViewModel
{
public int ID { get; set; }
public int? UserSearchID { get; set; }
public bool? Enabled { get; set; }
public SimpleDisplayFieldViewModel Property { get; set; }
public string Operator { get; set; }
public string CriteriaValue { get; set; }
}
public class SimpleDisplayFieldViewModel
{
public string Name { get; set; }
public string Value { get; set; }
public string PropertyType { get; set; }
}
In Angular, I submit a POST request to a WebAPI controller action with the following signature:
public IList<...> FindProducts(List<ProductCriteriaViewModel> criteriaVM, bool userFiltering)
{
...
}
In testing, I tried to send an array of Product Criterias, and checked Fiddler to see what the array looked like in the body of the POST request when it was being sent to the server. This is what the array looked like:
[
{"Enabled":true,
"Operator":"Less than",
"Property":
{"$id":"2",
"Name":"Copyright Year",
"Value":"Basic",
"PropertyType":null},
"CriteriaValue":"2013",
"IsNew":true},
{"Enabled":true,
"Operator":"Greater Than",
"Property":
{"$id":"2",
"Name":"Copyright Year",
"Value":"Basic",
"PropertyType":null},
"CriteriaValue":"1988",
"IsNew":true}
]
The above array has the correct values, however the result of deserialization on the server-side is incorrect. This is where it gets strange.
After the server deserializes the array and arrives in the controller action, the first element in criteriaVM is correct, all the values are set properly. However the second element is incorrect, CriteriaValue and Property are nulled out:
This issue only occurs whenever I choose the same search property for more than one criteria (i.e. Copyright < 2013 and Copyright > 1988). However, if I choose different properties (i.e. Copyright < 2013 and Price > 20), then all elements in the resulting criteriaVM are correctly initialized.
I do not understand what could be causing this issue. Why are only CriteriaValue and Property set to null in the second element of the List? Why does this issue only occur when I choose multiples of the same search properties?
Json.NET uses the keywords $id and $ref in order to preserve object references, so you are having troubles with your deserialization because your JSON has "$id" in the "Property" object. See this link for more information about object references.
In order to fix your deserialization issues, you can add the following line in the Register method of your WebApiConfig.cs class
config.Formatters.JsonFormatter.SerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
If your Web Api project does not include a WebApiConfig.cs class, simply add the configuration in your Global.asax:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;
Now your object in the web api method should look like this:
I have a Json service I cannot alter as it is not mine.
Their Json is a formatted in a way that parsing it is difficult. It looks something like this.
"people": {
"Joe Bob": {
"name": "Joe Bob",
"id": "12345"
},
"Bob Smith": {
"name": "Bob Smith",
"id": "54321"
}
},
I would really prefer this was laid out like a JSon array, however it presently is not.
I am wondering the best approach here. Should I alter the Json to look like an array before I parse it or load up the ExtensionData and parse it from that?
There are other items in the feed that I do not have issue with. Just stuck with this one section.
Thanks
You can use json.net to deserialize the data (the json you pasted, and doing only one parsing, without modifying anything).
using dynamic foo = JsonConvert.DeserializeObject<dynamic>(data)
than, you can iterate the list using foo.people, accessing the Name and Value.
you can create a class (if you know what the schema is, and to deserialize the data into a list of the given class such as:
public class People
{
[JsonProperty(PropertyName="people")]
public IDictionary<string, Person> Persons { get; set; }
}
public class Person
{
[JsonProperty(PropertyName="name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
}
and than call:
var obj = JsonConvert.DeserializeObject<People>(data);
foreach (var item in obj.Persons.Values)
{
//item is instance of Person
}
Another good and possible option will be:
How can I navigate any JSON tree in c#?
I have an issue where if my json file looks like this
{ "Numbers": "45387", "Words": "space buckets"}
I can read it just fine, however if it looks like this:
{ "Main" :{ "Numbers": "45387", "Words": "space buckets"},
"Something" :{"Numbers": "12345", "Words": "Kransky"} }
I get no information back. I have no idea how to switch between Main and Something!
Loading a JSON with this 'nested' information using this code,
var ser = new DataContractJsonSerializer(typeof(myInfo));
var info = (myInfo)ser.ReadObject(e.Result);
// The class being using to hold my information
[DataContract]
public class myInfo
{
[DataMember(Name="Numbers")]
public int number
{ get; set; }
[DataMember(Name="Words")]
public string words
{ get; set; }
}
Causes the class to come back empty.
I've tried adding the group name to DataContract eg. [DataContract, Name="Main"] but this still causes the classes values to be empty.
I've also tried adding "main" to the serializer overloader eg. var ser = new DataContractJsonSerializer(typeof(myInfo), "Main");
This causes an error: Expecting element 'Main' from namespace ''.. Encountered 'Element' with name 'root', namespace ''.
I'd prefer to just use the supplied json reader. I have looked into json.NET but have found the documentation to be heavy on writing json and sparse with information about reading.
Surely I'm missing something simple here!
You could add a wrapper class:
[DataContract]
public class Wrapper
{
[DataMember]
public myInfo Main { get; set; }
[DataMember]
public myInfo Something { get; set; }
}
Now you could deserialize the JSON back to this wrapper class and use the two properties to access the values.