none
How to convert data to a List<T> after reading from an existing JSON file? RRS feed

  • Question

  • Hi! 

    In my UWP app, I need to read from an existing .json file, convert that JSON data to a List<T>, add some new data to that List<T>, convert to that list to JSON data and write that data to that same existing .json file.

    How can I do that?

    Here is some code that I have written.

    private async void saveButton_Click(object sender, RoutedEventArgs e)
            {
                StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
                StorageFile samplefile = await storageFolder.CreateFileAsync
                    ("SavedData.json", CreationCollisionOption.ReplaceExisting);
                StorageFile savedFile = await storageFolder.GetFileAsync("SavedData.json");
                string text = await FileIO.ReadTextAsync(savedFile);
                var serializer = new DataContractJsonSerializer(typeof(DataFormat));
                var ms = new MemoryStream(Encoding.UTF8.GetBytes(text));
    
                List<DataFormat> data = (List<DataFormat>)serializer.ReadObject(ms);
    
                if (data == null)
                {
                    data = new List<DataFormat>();
                }
                data.Add(new DataFormat
                {
                    Title = fileText.Text,
                    Director = fileText1.Text,
                    Rated = fileText2.Text
                });
                Stream mystream = await savedFile.OpenStreamForWriteAsync();
                serializer.WriteObject(mystream, data);
            }


    DataFormat Class-

    public class DataFormat : IEquatable<DataFormat>
        {
            [DataMember]
            public string firstName { get; set; }
            [DataMember]
            public string lastName { get; set; }
            [DataMember]
            public string Country { get; set; }
    
            public bool Equals(DataFormat other)
            {
                string fullName = other.firstName + other.lastName;
                if (other == null)
                {
                    return false;
                }
    
                return (fullName.Equals(other.fullName));
            }
            
        }

    When I run this program, this exception appears -

    System.Runtime.Serialization.SerializationException was unhandled by user code
      HResult=-2146233088
      Message=Expecting element 'root' from namespace ''.. Encountered 'None'  with name '', namespace ''.
      Source=System.Private.DataContractSerialization
      StackTrace:
           at System.Runtime.Serialization.Json.DataContractJsonSerializerImpl.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)
           at System.Runtime.Serialization.XmlObjectSerializer.InternalReadObject(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
           at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
           at System.Runtime.Serialization.Json.DataContractJsonSerializerImpl.ReadObject(XmlDictionaryReader reader)
           at System.Runtime.Serialization.Json.DataContractJsonSerializerImpl.ReadObject(Stream stream)
           at System.Runtime.Serialization.Json.DataContractJsonSerializer.ReadObject(Stream stream)
           at UWP_TestingGround.MainPage.<saveButton_Click>d__2.MoveNext()
      InnerException: 


    [Note: I am new in C# so detailed information will be helpful.]


    • Edited by MahmudX Thursday, February 7, 2019 7:55 AM
    Thursday, February 7, 2019 7:54 AM

All replies

  • Hello,

    Create list of instances of your DataFormat and serialize them in JSON format to the file.

    Then try to deserialize created file.

    On the provided code, unless somebody have exactly the same situation, not possible to find out where is a problem - some code and data missing. 

    One of the possible problem - you creating/replacing a SavedData.json - file supposed to be empty after creation - and use this empty file as a source of data.


    Sincerely, Highly skilled coding monkey.

    Thursday, February 7, 2019 8:58 AM
  • Can you give an example? That will be very helpful Thanks.
    Thursday, February 7, 2019 10:50 AM
  • The code you posted cannot compile. You seem to be mixing code samples. In your DataFormat type you are referencing `other.fullName` which does not exist. In your main code you are creating a new instance of DataFormat and then assigning values to the `Title`, `Director`, and `Rating` properties which don't exist on this type.

    The call to SerializeObject is going to throw an exception if the JSON file isn't already a List<T>. You're doing a typecast. That throws an exception if it fails. You can use the 'as' operator to do a safe cast but it depends on how ReadObject works as to whether it'll succeed.

    var data = serializer.ReadObject(ms) as List<DataFormat>;

    Based upon your error it looks like the initial JSON isn't valid. When you created the serializer you specified the type of DataFormat but as I mentioned your code is trying to insert a completely different DataFormat type. This isn't going to work.

    If the contents don't line up with List<DataFormat> then it'll fail. Since you want the single item you're going to have to try reading the data again. Note the following code is for a .NET Framework app, UWP has slightly different types and is async. You'll need to adjust the code accordingly.

    class Program
    {
        static void Main ( string[] args )
        {
            AddToFile(@"test.json", new DataFormat()
            {
                firstName = "Sue",
                lastName = "Jones",
                country = "USA"
            });                                    
        }
    
        static void AddToFile ( string filename, DataFormat data )
        {
            List<DataFormat> items = null;
    
            //TODO: Using File class, replace with UWP equivalent
            var text = File.ReadAllText(filename);
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(text)))
            {
                items = ReadList(ms);                
            };
    
            //Add to it
            items.Add(data);
    
            //Save the list
            //TODO: Using File class here, replace with UWP equivalent
            using (var output = File.OpenWrite(filename))
            {
                WriteList(output, items);
            };
        }
    
        static List<DataFormat> ReadList ( Stream stream )
        {
            var serializer = new DataContractJsonSerializer(typeof(List<DataFormat>));
    
            try
            {                
                var items = serializer.ReadObject(stream) as List<DataFormat>;
                if (items?.Any() ?? false)
                    return items;
            } catch (SerializationException)
            {
                /* Ignore */
            };
    
            //Try and read the data as a single DataFormat item
            stream.Seek(0, SeekOrigin.Begin);
            var serializerSingle = new DataContractJsonSerializer(typeof(DataFormat));
            var item = serializerSingle.ReadObject(stream) as DataFormat;
            if (item != null)
                return new List<DataFormat>() { item };
    
            //Now what?
            throw new Exception("Unknown format");
        }
    
        static void WriteList ( Stream stream, List<DataFormat> data )
        {
            var serializer = new DataContractJsonSerializer(typeof(List<DataFormat>));
    
            serializer.WriteObject(stream, data);
        }
    }
    
    //Need this so the serializer will work
    [DataContract]
    public class DataFormat : IEquatable<DataFormat>
    {
        [DataMember]
        public string firstName { get; set; }
        [DataMember]
        public string lastName { get; set; }
        [DataMember]
        public string country { get; set; }
    
        [IgnoreDataMember]
        public string fullName => firstName + lastName;
    
        public bool Equals ( DataFormat other )
        {
            if (other == null)
                return false;
                            
            return (fullName.Equals(other.fullName));
        }
    
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, February 7, 2019 3:59 PM
    Moderator