How to store JSON data in Windows Phone 8

There have been a couple of forum questions on how to store JSON data and retrieve it in Windows Phone 8.  This post will explain how to do this with a simple example.  As a bonus I will show the code you can use to store a List of objects!

JSON serialization is a great way to store objects as a string and rebuild them from a string.  JSON is used by many WebServices and is also used with REST services such as Windows Azure Mobile Services.

Walkthrough

  • Create a new blank C# Windows Phone App in Visual Studio and target Windows Phone 8.0
  • Right click on the ‘References’ in the Solution Explorer and select ‘Manage NuGet Packages’
  • In the search box type json.net and select the Json.NET package pictured below and press the ‘Install’ button as pictured below
  • Note that this is not a Microsoft package and you should be sure you check out the link ‘View License Terms’

image

  • Create some simple XAML to Get and Set the JSON with buttons and display the Results in a TextBlock

Copy Code:

         <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
                <Button x:Name="btnGet" Tap="btnGet_Tap">Get JSON</Button>
                <Button x:Name="btnSet" Tap="btnSet_Tap">Set JSON</Button>
                <TextBlock x:Name="txtOut" TextWrapping="Wrap"></TextBlock>
            </StackPanel>
        </Grid>
  • Now add a class called ‘Product’ to your MainPage.xaml.cs file that will be ultimately what we will serialize (see code below)

Copy Code:

  public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double PriceUS { get; set; }
        public DateTime DateOrdered { get; set; }
    }
  • For simplicity I will create a class member to hold the current Product and initialize this in the constructor with some random values

Copy Code:

 // Product List we will serialize to and from
        List<Product> m_ProductList = null;
        
        string m_ProductFileName = "product.json";
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            m_ProductList = new List<Product>();
            Product aProduct = null;
            Random aRnd = new Random();

            for (int i = 0; i < 10; i++)
            {
                // Create a Product and intialize some values
                aProduct = new Product();
                aProduct.DateOrdered = DateTime.Now;
                aProduct.Id = aRnd.Next(1, 100);
                aProduct.Description = "Random Product";
                aProduct.PriceUS = aRnd.NextDouble();
                m_ProductList.Add(aProduct);
            }

            // Crude way to display the information for testing
            displayProduct();
        }
  • Finally add the code to display the product and stub out the button events for the get and set buttons.  Note that the button events are marked async as we will be executing async code in there when we add our next set of code.

Copy Code:

         //Displays the info very crudely 
        private void displayProduct()
        {
            txtOut.Text = string.Format(" Id: {0} \r\n DateOrdered: {1} \r\n Desc: {2} \r\n Price: {3:$0.00}",
                m_CurrentProduct.Id, m_CurrentProduct.DateOrdered.ToLongDateString(), 
                m_CurrentProduct.Description, m_CurrentProduct.PriceUS);
        }
        private async void btnGet_Tap(object sender, System.Windows.Input.GestureEventArgs e) 
        { 
        }
        private async void btnSet_Tap(object sender, System.Windows.Input.GestureEventArgs e) 
        { 
        }
  • So far we have not done any thing with JSON serialization.  Run the application and verify the product information displays in the text block

screenshot

You will notice each time you run the app, new values will be displayed for the Id and Price (and possibly date if you rolled passed Midnight)

Next we will do some serialization!

  • Create a class member to hold the file name we will use for serializing and de-serializing

Copy Code:

 string m_ProductFileName = "product.json"; 
  • Include the namespaces we will be using next

Copy Code:

 using Windows.Storage; using Windows.Storage.Streams; using Newtonsoft.Json;
  • Wire up the ‘Set JSON’ button to serialize the Current Product and save it to local storage

Copy Code:

 private async void btnSet_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {   
            // Serialize our Product class into a string             
            string jsonContents = JsonConvert.SerializeObject(m_CurrentProduct);
            // Get the app data folder and create or replace the file we are storing the JSON in.            
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            StorageFile textFile = await localFolder.CreateFileAsync(m_ProductFileName,
                                         CreationCollisionOption.ReplaceExisting);
            // Open the file...      
            using (IRandomAccessStream textStream = await textFile.OpenAsync(FileAccessMode.ReadWrite))
            {
                // write the JSON string!
                using (DataWriter textWriter = new DataWriter(textStream))
                {
                    textWriter.WriteString(jsonContents);
                    await textWriter.StoreAsync();
                }
            }
        }
  • Finally Wire up the ‘Get JSON’ button to de-serialize the string from the file into the Current Project object and display it

Copy Code:

 
    private async void btnGet_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            try
            {
                // Getting JSON from file if it exists, or file not found exception if it does not  
                StorageFile textFile = await localFolder.GetFileAsync(m_ProductFileName);
                using (IRandomAccessStream textStream = await textFile.OpenReadAsync())
                {
                    // Read text stream     
                    using (DataReader textReader = new DataReader(textStream))
                    {
                        //get size                       
                        uint textLength = (uint)textStream.Size;
                        await textReader.LoadAsync(textLength);
                        // read it                    
                        string jsonContents = textReader.ReadString(textLength);
                        // deserialize back to our product!  
                        m_CurrentProduct = JsonConvert.DeserializeObject<Product>(jsonContents);
                        // and show it                     
                        displayProduct();
                    }
                }
            }
            catch (Exception ex)
            {
                txtOut.Text = "Exception: " + ex.Message;
            }
        }

Test

Using the Windows Phone Power tools you can see the product.json file get created during testing.  You will need to know your product id which is in your WMAppManifest.xml file (use View Code to see it in XML format).  You can then select the correct app if there is more than one installed.  See below.

image

Once you ‘Set JSON’ you need to right click on your app ID and choose refresh.  You can then double click on product.json and view it in Notepad if you wish to see the contents.

image

You should be able to set the json file, stop debugging, start the app again and use the ‘Get JSON’ button to read the file back.

Advanced topic: Lists of JSON Data

Arrays and Lists are not that much more difficult.  You simply need to declare a List or Array and serialize that data.  Below is a complete listing of the modifications I made to generate a List of products, serialize and de-serialize that list:

Copy Code:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PhoneApp1.Resources;
using Windows.Storage;
using Windows.Storage.Streams;
using Newtonsoft.Json;
using System.Text;

namespace PhoneApp1
{
    public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double PriceUS { get; set; }
        public DateTime DateOrdered { get; set; }
    }

    public partial class MainPage : PhoneApplicationPage
    {
        // Product List we will serialize to and from
        List<Product> m_ProductList = null;

        string m_ProductFileName = "product.json";
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            m_ProductList = new List<Product>();
            Product aProduct = null;
            Random aRnd = new Random();

            for (int i = 0; i < 10; i++)
            {
                // Create a Product and intialize some values
                aProduct = new Product();
                aProduct.DateOrdered = DateTime.Now;
                aProduct.Id = aRnd.Next(1, 100);
                aProduct.Description = "Random Product";
                aProduct.PriceUS = aRnd.NextDouble();
                m_ProductList.Add(aProduct);
            }

            // Crude way to display the information for testing
            displayProduct();
        }

        // Displays the info very crudely
        private void displayProduct()
        {
            txtOut.Text = "";
            StringBuilder productsString = new StringBuilder();
            foreach (Product aProduct in m_ProductList)
            {
                productsString.AppendFormat(" Id: {0} \r\n DateOrdered: {1} \r\n Desc: {2} \r\n Price: {3:$0.00} \r\n",
                    aProduct.Id, aProduct.DateOrdered.ToLongDateString(),
                    aProduct.Description, aProduct.PriceUS);
            }

            txtOut.Text = productsString.ToString();
        }

        private async void btnGet_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {

            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            try
            {
                // Getting JSON from file if it exists, or file not found exception if it does not
                StorageFile textFile = await localFolder.GetFileAsync(m_ProductFileName);

                using (IRandomAccessStream textStream = await textFile.OpenReadAsync())
                {
                    // Read text stream 
                    using (DataReader textReader = new DataReader(textStream))
                    {
                        //get size
                        uint textLength = (uint)textStream.Size;
                        await textReader.LoadAsync(textLength);
                        // read it
                        string jsonContents = textReader.ReadString(textLength);
                        // deserialize back to our products!
                        //I only had to change this following line in this function
                        m_ProductList = JsonConvert.DeserializeObject<IList<Product>>(jsonContents) as List<Product>;
                        // and show it
                        displayProduct();
                    }
                }
            }
            catch (Exception ex)
            {
                txtOut.Text = "Exception: " + ex.Message;
            }
        }


        private async void btnSet_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            // Serialize our Product class into a string
            // Changed to serialze the List
            string jsonContents = JsonConvert.SerializeObject(m_ProductList);

            // Get the app data folder and create or replace the file we are storing the JSON in.
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            StorageFile textFile = await localFolder.CreateFileAsync(m_ProductFileName, CreationCollisionOption.ReplaceExisting);

            // Open the file...
            using (IRandomAccessStream textStream = await textFile.OpenAsync(FileAccessMode.ReadWrite))
            {
                // write the JSON string!
                using (DataWriter textWriter = new DataWriter(textStream))
                {
                    textWriter.WriteString(jsonContents);
                    await textWriter.StoreAsync();
                }
            }
        }
    }
}

Conclusion

I demonstrated how to serialize JSON data in a Windows Phone App.  It is easy to serialize your class objects using JSON and using this technique allows you to store your class data easily for offline situations or to keep state information for your class data!

As a side note, you can use similar techniques in your Windows Store app!

Let me know if this was helpful!

Follow us at @WSDevSol