I'm loading categories from an ASP.NET Core backend as an array into a Xamarin app for a ListView with grouped items like here https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/customizing-list-appearance#grouping.
09-06 23:25:36.679 W/SSLCertificateSocketFactory(29717): Bypassing SSL security checks at caller's request
[0:] Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'BoerPlaza.Models.Products.Category' 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<T>) 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 '[0].id', line 1, position 7.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x003a0] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x0006d] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList (System.Collections.IList list, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonArrayContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, System.String id) [0x00173] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.Object existingValue, System.String id) [0x000dc] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x0007f] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, System.Boolean checkAdditionalContent) [0x000db] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00054] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.JsonSerializer.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType) [0x00000] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.JsonConvert.DeserializeObject (System.String value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) [0x0002d] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <2073514815234917a5e8f91b0b239405>:0
at Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value) [0x00000] in <2073514815234917a5e8f91b0b239405>:0
at BoerPlaza.Services.CategoryDataStore.GetCategoriesParentAsync () [0x0013b] in C:\Users\QuanDar\source\repos\BoerPlaza\Frontend\BoerPlaza\BoerPlaza\Services\CategoryDataStore.cs:47
at BoerPlaza.ViewModels.BrowseCategoryViewModel.ExecuteLoadCategoriesCommand () [0x00068] in C:\Users\QuanDar\source\repos\BoerPlaza\Frontend\BoerPlaza\BoerPlaza\ViewModels\BrowseCategoryViewModel.cs:49
The problem with the model is that you have to inherit from ObservableCollection. All the other models are working fine, it's just this one I can't make work because of the inheritance. When I remove the inheritance, everything works great, but I can't group my items in the ListView then.
Tried List instead of ObservableCollection. Does not matter. Xamarin Model: (EF Core model not included, but JSON should show what is available)
public class Category : ObservableCollection<Category>
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public Category Parent { get; set; }
public Image Image { get; set; }
public ObservableCollection<Category> Children => this;
public Category(string title)
{
this.Title = title;
}
public Category()
{
}
}
JSON from backend:
[
{
"id": 1,
"title": "Vlees",
"description": null,
"parent": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": [
{
"id": 5,
"title": " Kip",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
},
{
"id": 6,
"title": "Koe",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
}
]
},
{
"id": 2,
"title": "Groente",
"description": null,
"parent": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": [
{
"id": 9,
"title": "Boemkool",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
}
]
},
{
"id": 3,
"title": "Fruit",
"description": null,
"parent": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": [
{
"id": 10,
"title": "Appel",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
},
{
"id": 11,
"title": "Peer",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
}
]
},
{
"id": 4,
"title": "Kruiden",
"description": null,
"parent": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": [
{
"id": 12,
"title": "Knoflook",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
},
{
"id": 13,
"title": "Peterselie",
"description": null,
"image": {
"alt": "Bedrijven WordPress themes",
"pathThumbnail": "Templates/constructie.jpg"
},
"children": []
}
]
}
]
HTTP Service
public async Task<IEnumerable<Category>> GetCategoriesParentAsync()
{
if (IsConnected)
{
var json = await client.GetStringAsync($"api/products/categories/parent");
return await Task.Run(() => JsonConvert.DeserializeObject<IEnumerable<Category>>(json));
}
return this.categories;
}
ViewModel: When I set the array myself, everything works fine.
public ObservableCollection<Category> Categories { get; set; }
...
public async Task ExecuteLoadCategoriesCommand()
{
IsBusy = true;
this.PreviousCategoryHolder.Add(this.Categories);
try
{
Categories.Clear();
// This does not work and throws the error
//var categories = await CategoryStore.GetCategoriesParentAsync();
//foreach (var category in categories)
//{
// Categories.Add(category);
//}
// when I do it like this, it works and displays the items.
this.Categories = new ObservableCollection<Category>
{
new Category("Vlees")
{
new Category("kip"),
new Category("kip file")
},
new Category("Groente")
{
new Category("Appel"),
new Category("Banaan")
}
};
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BoerPlaza.Views.BrowsePage">
<!-- binding context is in code behind -->
<ContentPage.Content>
<ListView x:Name ="categoriesListView"
IsGroupingEnabled="true"
ItemTapped="Handle_ItemTapped"
CachingStrategy="RecycleElement"
>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"/>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
Thanks!