user470760
user470760

Reputation:

Dictionary of Objects doesn't work as JSON

I have spent WAY too much time trying to figure out how to pull all the values I need to from my C# application using JS and JSON. It works fine when I just use simple structures, such as an array, but I need to be able to grow the list at runtime.

Right now, the best I could figure out was doing a Dictionary with an incrementing key value, and the other 3 values as a class object. However, this seems to crash out my C# application.

What would be the best way to do this?

Relevant C# Code:

public class ChatData
{
    string userName;
    string message;
    System.DateTime timestamp;

    public ChatData(string name, string msg)
    {
        userName = name;
        message = msg;
        timestamp = System.DateTime.Now;
    }
}

        else if (string.Equals(request, "getchat"))
        {
            //string since = Request.Query.since;

            Dictionary<int, ChatData> data = new Dictionary<int, ChatData>();

            data.Add(1, new ChatData("bob", "hey guys"));
            data.Add(2, new ChatData("david", "hey you"));
            data.Add(3, new ChatData("jill", "wait what"));

            return Response.AsJson(data);
        }

Relevant Javascript:

function getChatData()
{
    $.getJSON(dataSource + "?req=getchat", "", function (data)
    {
        //$.each(data, function(key, val)
        //{
            //addChatEntry(key, val);
        //})
    });
}

Upvotes: 3

Views: 6177

Answers (2)

tvanfosson
tvanfosson

Reputation: 532575

Why not simply use a typed list? Also, you'll need a default constructor to serialize/deserialize it. Note how I've modified your class to use properties as well. Note, as @rudolf_franek mentions, you can add an ID property to the ChatData class if you need to be able to link to it.

public class ChatData
{
     public ChatData()
     {
         TimeStamp = DateTime.Now;
     }
     public int ID { get; set; }
     public string Who { get; set; }
     public string Said { get; set; }
     public DateTime TimeStamp { get; set; }
}

...

var data = new List<ChatData>
{
    new ChatData { ID = 1, Who = "bob", Said = "hey guys" },
    ...
};

return Response.AsJson( data );

Upvotes: 2

Darin Dimitrov
Darin Dimitrov

Reputation: 1039100

You haven't explained what Response.AsJson is and how it is implemented but if it uses JavaScriptSerializer you will get the following exception:

Unhandled Exception: System.ArgumentException: Type 'System.Collections.Generic. Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[ChatData, Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' is not supported for serialization/deserialization of a dictionary, keys must be strings or objects.

which is pretty self-explanatory. You cannot use integers as keys if you intend to JSON serialize this structure. Also because your ChatData class no longer has a default/parameterless constructor you won't be able to deserialize a JSON string back to this class (but I guess you don't need this yet).

So one possible solution to your problem would be to use:

Dictionary<string, ChatData> data = new Dictionary<string, ChatData>();
data.Add("1", new ChatData("bob", "hey guys"));
data.Add("2", new ChatData("david", "hey you"));
data.Add("3", new ChatData("jill", "wait what"));

Now of course this being said and looking at the javascript you commented out and what you intend to do, as I already explained you in your previous question, dictionaries are not serialized as javascript arrays, so you cannot loop over them.

Long story short, define a class:

public class ChatData
{
    public string Username { get; set; }
    public string Message { get; set; }
    public DateTime TimeStamp { get; set; }
}

and then fill an array of this class:

var data = new[]
{
    new ChatData { Username = "bob", Message = "hey guys" },
    new ChatData { Username = "david", Message = "hey you" },
    new ChatData { Username = "jill", Message = "wait what" },
};
return Response.AsJson(data);

and finally consume:

$.getJSON(dataSource, { req: 'getchat' }, function (data) {
    $.each(data, function(index, element) {
        // do something with element.Username and element.Message here, like
        $('body').append(
            $('<div/>', {
                html: 'user: ' + element.Username + ', message:' + element.Message
            })
        );
    });
});

Upvotes: 3

Related Questions