C# Deserialize JSON file and show in Xamarin Android listview via adapter

Jeff Heilman
Jeff Heilman used Ask the Experts™
on
I have a json file "inventory.json" file that I am trying to show in an xamarin android listview but am having trouble understanding the adapter.  Here is my code which is throwing this error:  Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[ProfilesScan.Model.SelectInvItemlist]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

public class EOMSelectItemActivity : Activity

    {
        public Button _btnSelect;
        public ListView _listView1;
        public TextView _txtFilter;
        public string jsonString;
        public string inventoryitems;
        private ArrayAdapter<string> adapter;
        public string items;
        private List<string> invItems;
                

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate (savedInstanceState);
            SetContentView(Resource.Layout.EOMSelectItem);

            _listView1 = FindViewById<ListView>(Resource.Id.listView1);
            

            string filePath = Path.Combine(FileSystem.Current.LocalStorage.Path + "inventory.json");

            invItems = new List<string>();
            invItems.Add(items);

            var jsonContents = System.IO.File.ReadAllText(filePath);
            items = JsonConvert.DeserializeObject(jsonContents).ToString();

            ArrayAdapter<string> adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, invItems);

            _listView1.Adapter = adapter;

            //TextView txtFilter = FindViewById<TextView>(Resource.Id.txtFilter);

        }

Open in new window


Here are the classes I'm trying to use:
 public class SelectInvItem
    {
        [JsonProperty("Olditem")]
        public string Olditem { get; set; }
        
    }

    public class SelectInvItemlist
    {
        [JsonProperty("GetSelectInvListResult")]
        public IList<SelectInvItem> SelectinvItemResult { get; set; }

Open in new window


And here is a sample of the JSON data returned from my web service:
{  
   "GetInvListResult":[  
      {  
         "Description":"PLASTIC WRAP FOR FENCING 14' x 200' x .005 ML  ( SF145WU) NEW WHITE PLASTIC",
         "Inventoryitem":"NEW WHITE PLASTIC",
         "Lbsperunit":1,
         "Olditem":" SF145WU",
         "Onhand":0,
         "Uom":"Roll"
      },
      {  
         "Description":"GAYLORD LINERS,(10215)",
         "Inventoryitem":"200000666606",
         "Lbsperunit":1,
         "Olditem":"10215",
         "Onhand":76,
         "Uom":"Roll"
      },
      {  
         "Description":"(105949) AWT3, TAPE,GLAZING,INLINE, BLACK DSA 1\/8\" X 3\/8\" X 1200'",
         "Inventoryitem":"AWT3",
         "Lbsperunit":1,
         "Olditem":"105949",
         "Onhand":0,
         "Uom":"Roll"
      },
      {  
         "Description":"ROSCOM FLEX TAN US BLOCK (110415-5582-UVF-75 TAN498)",
         "Inventoryitem":"110415-5582-UVF-75 TAN498",
         "Lbsperunit":1,
         "Olditem":"110415-5582-UVF-75 TAN498",
         "Onhand":1354,
         "Uom":"Lb"
      },
      {  
         "Description":"GREEN PLASTIC BANDING (2040HGE)",
         "Inventoryitem":"200000111102",
         "Lbsperunit":1,
         "Olditem":"2040HGE",
         "Onhand":14,
         "Uom":"Roll"
      },
      {  
         "Description":"CIRCLE REELS 1\"X 6\" X 16\" (20563)",
         "Inventoryitem":"20563",
         "Lbsperunit":1,
         "Olditem":"20563",
         "Onhand":0,
         "Uom":"Units"
      },
      {  
         "Description":"PP 3\/4\"   PROTECTIVE FILM 64\/ CS (58900075B)",
         "Inventoryitem":"58900075B",
         "Lbsperunit":1,
         "Olditem":"58900075B",
         "Onhand":0,
         "Uom":"Units"
      },
      {  
         "Description":"PP 1 1\/2\" PROTECTIVE FILM 32R\/C  (5890015B)",
         "Inventoryitem":"5890015B",
         "Lbsperunit":1,
         "Olditem":"5890015B",
         "Onhand":0,
         "Uom":"Units"
      },
      {  
         "Description":"PP 1\" PROTECTIVE FILM (589001B)",
         "Inventoryitem":"589001B",
         "Lbsperunit":1,
         "Olditem":"589001B",
         "Onhand":0,
         "Uom":"Units"
      },
      {  
         "Description":"PP 2 1\/2 \" PROTECTIVE FILM 20R\/C  (5890025B)",
         "Inventoryitem":"5890025B",
         "Lbsperunit":1,
         "Olditem":"5890025B",
         "Onhand":0,
         "Uom":"Units"
      },
      {  
         "Description":"PP 2\" PROTECTIVE FILM  24R\/C (589002B)",
         "Inventoryitem":"589002B",
         "Lbsperunit":1,
         "Olditem":"589002B",
         "Onhand":0,
         "Uom":"Units"
      },
      {  
         "Description":"PP 3 \" PROTECTIVE FILM  16R\/C (589003B)",
         "Inventoryitem":"589003B",
         "Lbsperunit":1,
         "Olditem":"589003B",
         "Onhand":0,
         "Uom":"Units"
      },

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
kaufmedGlanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015

Commented:
Your data is not an array, hence the error. Your data is an object, which has a single property, and that property has a value that is an array. You need to modify your code to deserialize something that matches that structure. You can use a tool like json2csharp.com to generate the appropriate class structure:

e.g.
public class GetInvListResult
{
    public string Description { get; set; }
    public string Inventoryitem { get; set; }
    public int Lbsperunit { get; set; }
    public string Olditem { get; set; }
    public int Onhand { get; set; }
    public string Uom { get; set; }
}

public class RootObject
{
    public List<GetInvListResult> GetInvListResult { get; set; }
}

Open in new window


Then, just change the type of thing you're deserializing:

RootObject instance = JsonConvert.DeserializeObject<RootObject>(jsonContents);

Open in new window


Then you'll have a POCO that you can use to access the items:

List<GetInvListResult> items = instance.GetInvListResult;
GetInvListResult firstItem = items[0];
string description = firstItem.Description;

Open in new window

Jeff HeilmanBusiness Systems Mgr

Author

Commented:
Thanks so much for your response kaufmed.  I feel it has gotten me closer to achieving the goal.  However I am having an issue with the adapter.  Could you advise me as to how it should be set up?  Even better how would I be able to show just the Olditem column in the ListView?  I greatly appreciate your help.
namespace ProfilesScan.Activities
{
    [Activity(Label = "EOMSelectItemActivity", Theme = "@style/Theme.AppCompat.Light.NoActionBar", MainLauncher = false)]
    public class EOMSelectItemActivity : Activity

    {
        public Button _btnSelect;
        public ListView _listView1;
        public string items;
 
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.EOMSelectItem);

            _listView1 = FindViewById<ListView>(Resource.Id.listView1);

            string filePath = Path.Combine(FileSystem.Current.LocalStorage.Path + "inventory.json");

            var jsonContents = System.IO.File.ReadAllText(filePath);
            RootObject instance = JsonConvert.DeserializeObject<RootObject>(jsonContents);

            List<GetInvListResult> items = instance.GetInvListResult;

            [b]ArrayAdapter<string> adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, items);[/b]

            _listView1.Adapter = adapter;
        }

Open in new window

kaufmedGlanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015

Commented:
What is the issue/error you are having?
Why Diversity in Tech Matters

Kesha Williams, certified professional and software developer, explores the imbalance of diversity in the world of technology -- especially when it comes to hiring women. She showcases ways she's making a difference through the Colors of STEM program.

Jeff HeilmanBusiness Systems Mgr

Author

Commented:
I have set up the adapter like this:  
ArrayAdapter<GetInvListResult> adapter = new ArrayAdapter<GetInvListResult>(this, Android.Resource.Layout.SimpleListItem1, items);

Open in new window


What I'm getting on the list is : ProfilesScan.Model.GetInvListResult.  The good news is that there appears to be one for every item.  Ultimately what I would like to do is show a list showing the Olditem only.  Thanks again!
Glanced up at my screen and thought I had coded the Matrix...  Turns out, I just fell asleep on the keyboard.
Most Valuable Expert 2011
Top Expert 2015
Commented:
You can either override the ToString method to return the property you care about:

public class GetInvListResult
{
    public string Description { get; set; }
    public string Inventoryitem { get; set; }
    public int Lbsperunit { get; set; }
    public string Olditem { get; set; }
    public int Onhand { get; set; }
    public string Uom { get; set; }

    public override string ToString()
    {
        return this.Description;
    }
}

Open in new window


...Or you can modify the list before assigning it to the ArrayAdapter:

ArrayAdapter<string> adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, items.Select(item => item.Description).ToArray());

Open in new window

Jeff HeilmanBusiness Systems Mgr

Author

Commented:
Thanks for your patience kaufmed, you are awesome!  Have a great day! -Jeff

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial