AgFx in combination with JSON.Net

Mar 15, 2012 at 8:24 PM

Hi All,

Using AgFx looks great, all is working smoothly using the samples.

However, I'm interested in using AgFx in my application, but it does not work with JSON.Net

I'm using a web-service that supports JSON, currently I'm using Restsharp requests (tried base requests as well) However, I'm not using ViewModels like shown in the examples, but using ViewModels for MVVM. The ViewModels in AgFx terms are Models in my application.

When I now try to load my data Models, they are not getting deserialized... When I try the same without the ModelItemBase, the deserialization works.

What should I do to make this work?

Hope anyone can help.

Pieter

Coordinator
Mar 15, 2012 at 8:58 PM

HI Peter -

JSON.net should be fine - you'd use that from within your Deserialize method to take the stream and parse the JSON.  

Can you paste in a sample of what you're trying to do?


Thanks,

Shawn

Mar 15, 2012 at 10:01 PM
Edited Mar 15, 2012 at 10:01 PM

Based on your Flickr sample, using this method to deserialize:

public class Note //: INotifyPropertyChanged 
        : ModelItemBase 
    {
        public Note()
        {
            
        }
        
        public Note(int noteId)
            :this()
        {
            this.LoadContext = new LoadContext(noteId);
        }
        /*
        public int NoteId
        {
            get { return (int) this.LoadContext.Identity; }
        }
        */
        
        private int _noteId;
        public int NoteId
        {
            //get { return _noteId; }
            get { return (int)this.LoadContext.Identity; }
            set
            {
                if (_noteId == value) return;

                _noteId = value;
                RaisePropertyChanged("NoteId");
            }
        }
        
        private string _title;
        public string Title
        {
            get { return _title; }
            set
            {
                if (_title == value) return;

                _title = value;
                RaisePropertyChanged("Title");
            }
        }

        private string _description;
        public string Description
        {
            get { return _description; }
            set
            {
                if (_description == value) return;

                _description = value;
                RaisePropertyChanged("Description");
            }
        }

        private DateTime _dateCreated;
        public DateTime DateCreated
        {
            get { return _dateCreated; }
            set
            {
                if (_dateCreated == value) return;

                _dateCreated = value;
                RaisePropertyChanged("DateCreated");
            }
        }

        private DateTime _dateModified;
        public DateTime DateModified
        {
            get { return _dateModified; }
            set
            {
                if (_dateModified == value) return;

                _dateModified = value;
                RaisePropertyChanged("DateModified");
            }
        }


        // User (Author)
        private int _userId;
        public int UserId
        {
            get { return _userId; }
            set
            {
                if (_userId == value) return;

                _userId = value;
                RaisePropertyChanged("UserId");
            }
        }
/*
        #region INotifyPropertyChanged Members

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(prop));
            }
        }

        #endregion
*/
    }
}

...
...
protected override object DeserializeCore(LoadContext loadContext, Type objectType, Stream stream)
            {
                using (var reader = new StreamReader(stream, Encoding.UTF8))
                {
                    var text = reader.ReadToEnd();
                    var note = JsonConvert.DeserializeObject<Note>(text);

                    return note;
                }
            }

Mar 15, 2012 at 10:03 PM
Edited Mar 15, 2012 at 10:04 PM

As you can see in the code above, I tried both the normal INotifyPropertyChanged, this works.

However, when using the ModelItemBase it doesn't work.

I also tried several ways of deserialization through JSON.

Using the following code, I can read out the JSON value:

 

protected override object DeserializeCore(LoadContext loadContext, Type objectType, Stream stream)
            {
                using (var reader = new StreamReader(stream, Encoding.UTF8))
                {
                    var jsonReader = new JsonTextReader(reader);

                    // Load JObject from stream
                    JObject jObject = JObject.Load(jsonReader);

                    // Create target object based on JObject
                    Note target = new Note();

                    var serializer = new Newtonsoft.Json.JsonSerializer();
                    // Populate the object properties
                    serializer.Populate(jObject.CreateReader(), target);

                    return target;
                }
            }
Coordinator
Mar 16, 2012 at 5:07 PM

Well one thing I notice is that the LoadContext for the new Note isn't set in either case.

The NoteId property reads out of the LoadContext, but doesn't push into it.

Both of those cases are going to use the default ctor, so maybe that's part of the problem.  I'm not sure I understand with the INotifyPropertyChanged implementation has to do with it, since ModelItemBase already implements that.

In any case, I'd verify that the object that's being returned from DeserializeCore is property formatted, has a LoadContext that matches it's ID, etc.

An easy way to do this would be the following:

 

protected override object DeserializeCore(LoadContext loadContext, Type objectType, Stream stream)
            {
                using (var reader = new StreamReader(stream, Encoding.UTF8))
                {
                    var jsonReader = new JsonTextReader(reader);

                    // Load JObject from stream
                    JObject jObject = JObject.Load(jsonReader);

                    // Create target object based on JObject
                    Note target = new Note(jObject.getInt('id')); // I'm guessing at the syntax for JSON.net here.

                    var serializer = new Newtonsoft.Json.JsonSerializer();
                    // Populate the object properties
                    serializer.Populate(jObject.CreateReader(), target);

                    return target;
                }
            }

 

 

Mar 16, 2012 at 8:02 PM

Hi Shawn,

There might be a misinterpretation of my code. 

The sample given above works, this is without the ModelItemBase. With the ModelItemBase, I use the code:

Note Target = new Note(loadContext.Identity);

However, with the ModelItemBase it does not serialize.

For now I have found a workaround, for each model I have applied the following:

[JsonObject(MemberSerialization.OptIn)]
[CachePolicy(CachePolicy.CacheThenRefresh, 60 * 5)]
public class Note : ModelItemBase 
{
        public Note()
        {
            
        }
        
        public Note(object noteId)
            :this()
        {
            this.LoadContext = new LoadContext(noteId);
        }

        [JsonProperty]
        public int NoteId
        {
            get { return (int)this.LoadContext.Identity; }
            set
            {
                if (LoadContext == null || LoadContext.Identity == null)
                    this.LoadContext = new LoadContext(value);

                RaisePropertyChanged("NoteId");
            }
        }

        private string _title;
        [JsonProperty]
        public string Title
        {
            get { return _title; }
            set
            {
                if (_title == value) return;

                _title = value;
                RaisePropertyChanged("Title");
            }
        }
}

This works, since now JSON.Net only looks to the properties that need to be (de)serialized.

This leads me to think the problem lies in the ModelItemBase.

Hope you can find a solution.

Kind regards,

Pieter

Mar 16, 2012 at 8:02 PM

Ps. This is the code I'm using for deserialization.

public class NoteDataLoader : RelationDataLoaderBase
        {
            public override LoadRequest GetLoadRequest(LoadContext loadContext, Type objectType)
            {
                return BuildRequest(loadContext, string.Format("Notes/{0}", loadContext.Identity));
            }

            protected override object DeserializeCore(LoadContext loadContext, Type objectType, Stream stream)
            {
                using (var reader = new StreamReader(stream, Encoding.UTF8))
                {
                    var target = new Note(loadContext.Identity);

                    JsonConvert.PopulateObject(reader.ReadToEnd(), target);

                    return target;
                }
            }
        }

Coordinator
Mar 17, 2012 at 4:50 AM

Looking at the ModelItemBase code, I don't see anything in there that the JSON deserializer should be mucking with.

When you say "With ModelItemBase it does not serialize", do you mean that with a plain ModelItemBase, the property values don't get set from what's in the JSON stream?

If this is the case then I suspect the problem has to do with the DataContractAttribute on NotifyPropertyChangedBase.  Typically, when an object has [DataContract], serailizers flip to explicit mode, JSON.NET may be honoring this, hence the behavior you're seeing.

Now if that's the case (maybe do a build of AgFx with that commented out), then you have the right fix.  On the other hand, I'm not sure why that attribute is there.  I poked around in the AgFx code a bit and I don't see any usages of DataContractSerializer, and all the unit tests pass.  Disclaimer: I didn't try the sample apps because the emulator does't work on my current set up.  You might want to give that a shot, but in any case give it a show without it.