问题
I'm a beginner in C # and Xamarin. I'm trying to deserialize json arrays with newtonsoft? Here is my json file:
{
"next": {
"$ref": "http://192.168.0.100:8080/ords/hr/employees/?page=1"
},
"items": [
{
"empno": 7369,
"ename": "SMITH",
"job": "CLERK",
"mgr": 7902,
"sal": 800,
"deptno": 20
},
{
"empno": 7934,
"ename": "MILLER",
"job": "CLERK",
"mgr": 7782,
"sal": 1300,
"deptno": 10
}
]
}
Her is my model class:
public class RootObject
{
[JsonProperty("items")]
public Item[] Items { get; set; }
[JsonProperty("next")]
public Next Next { get; set; }
}
public class Next
{
[JsonProperty("$ref")]
public string Ref { get; set; }
}
public class Item
{
[JsonProperty("deptno")]
public long Deptno { get; set; }
[JsonProperty("empno")]
public long Empno { get; set; }
[JsonProperty("ename")]
public string Ename { get; set; }
[JsonProperty("job")]
public string Job { get; set; }
[JsonProperty("mgr")]
public long Mgr { get; set; }
[JsonProperty("sal")]
public long Sal { get; set; }
}
When I try deserialize into a List it throws exception on this line:
var data = JsonConvert.DeserializeObject<List<RootObject>>(json);
The error is:
Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[System.Object]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) 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.
This code desirialize the Json, but I don't now retrive the data and populate the class:
public class ApiServices {
public async Task<RootObject> GetRootObject()
{
var client = new HttpClient();
var url = string.Format("http://mysite/ords/hr/employees");
var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
dynamic jsonDe = JsonConvert.DeserializeObject<RootObject>(json);
return jsonDe;
}
I have already created some code in MainViewModel, but I do not know how to retrieve the data and insert the class Item:
public class MainViewModel
{
#region Properties
public ObservableCollection<RootItemViewModel> RootObjects { get; set; }
private ApiServices apiServices;
#endregion
#region Constructors
public MainViewModel()
{
//Create observable collections
RootObjects = new ObservableCollection<RootItemViewModel>();
//Instance services
apiServices = new ApiServices();
//Load Data
LoadData();
}
#endregion
#region Methods
private async void LoadData()
{
var emps = new RootObject();
emps = await apiServices.GetRootObject();
RootObjects.Clear();
foreach (var item in RootObjects)
{
RootObjects.Add(new RootItemViewModel
{
});
}
}
#endregion
}
}
The class RootItemViewModel:
public class RootItemViewModel : RootObject
{
}
回答1:
1) Your Json response shows, that it just holds an instance of the type RootObject
.
2) var data = JsonConvert.DeserializeObject<List<RootObject>>(json);
will not work therefore, because you try to cast a RootObject
to a List<RootObject>
. Described in your error response.
3) dynamic jsonDe = JsonConvert.DeserializeObject<RootObject>(json);
will work because here you cast a RootObject
to a RootObject
. I also suggest you tu use "var" instead of "dynamic" (see why: dynamic vs var)
4) your following method seems to have a mistake in there:
private async void LoadData()
{
var emps = new RootObject();
emps = await apiServices.GetRootObject();
RootObjects.Clear();
//Mistake:
//You iterate through the previously cleared observable collection.
//it really should be "foreach (var item in emps.Items)"
foreach (var item in RootObjects)
{
RootObjects.Add(new RootItemViewModel
{
});
}
}
5) It looks like you wanted to feed the observable collection with the array of type Item
on your RootObject
:
public class RootObject
{
[JsonProperty("items")]
public Item[] Items { get; set; } //This property
[JsonProperty("next")]
public Next Next { get; set; }
}
So what you actually should be doing is setting the data like this:
private async void GetRootObjectItems()
{
RootObject emps = await apiServices.GetRootObject(); //Get the root object
RootObjects.Clear(); //clear the list
foreach (var item in emps.Items) //Important, to get the data from the Array on the RootObject
{
///its a nice way to give your viewmodel a ctor signature that ensures a correct initialization
///public RootItemViewModel(Item item)
///{
/// this.Deptno = item.Deptno;
///}
RootObjects.Add(new RootItemViewModel(item));
}
}
}
6) It makes no sense for your RootItemViewModel
to inherit from RootObject
. You should make it inherit from Item
or have it hold a property of type Item
.
I hope I could clear things up!
回答2:
For this JSON:
{
"next": {
"$ref": "http://192.168.0.100:8080/ords/hr/employees/?page=1"
},
"items": [
{
"empno": 7369,
"ename": "SMITH",
"job": "CLERK",
"mgr": 7902,
"sal": 800,
"deptno": 20
},
{
"empno": 7934,
"ename": "MILLER",
"job": "CLERK",
"mgr": 7782,
"sal": 1300,
"deptno": 10
}
]
}
Use this Class:
internal class SomeObject{ //in C# you can even NOT to define internal as well :)
public class next{
public string ref {get; set;} //var do not use $, you need to change the JSON code or you nned to make a custom reader for that.
}
public List<Item> items {get; set;}
public class Item{
public string empno {get; set;}
public string ename {get; set;}
public string job {get; set;}
public string mgr {get; set;}
public string sal {get; set;}
public string deptno {get; set;}
}
}
To deserialize those JSON to a Class, use this one:
var obj = JSONConvert.DeserializeObject<SomeObject>(json); //json is a string of your JSON
//Now you can access the data like
listView.ItemsSource = obj.Items; //for mobile listview
You cannot put List because the JSON object is not pure List Of object, it is combined object between next object and items object. So you need to create a class first before putting the JSON into list.
回答3:
http://json2csharp.com/ is always useful, ( quick way to get the class 'skeleton' )
like 'Mr Hery' wrote you might have to do a custom reader or remove the $ sign - if you are generating the json output yourself.
public class Next
{
public string @ref { get; set; }
}
public class Item
{
public int empno { get; set; }
public string ename { get; set; }
public string job { get; set; }
public int mgr { get; set; }
public int sal { get; set; }
public int deptno { get; set; }
}
public class RootObject //(rename class you something better like Employees)
{
public Next next { get; set; }
public List<Item> items { get; set; }
}
For Deserializing :
var data = JsonConvert.DeserializeObject<RootObject>(json);
or
var _employees = JsonConvert.DeserializeObject<Employees>(json);
来源:https://stackoverflow.com/questions/47615299/deserialize-json-using-newtonsoft-and-biding-view-mvvm