Mustafa Ekici
Mustafa Ekici

Reputation: 7470

How to parse Dictionary type with json-ajax

I have Dictionary which will return from server, i converted it json string format as below:

public static class Extensions 
{ 
    public static string ToJson<T>(this T obj) 
    { 
        MemoryStream stream = new MemoryStream(); 
        try { 
            DataContractJsonSerializer jsSerializer = new DataContractJsonSerializer(typeof(T)); 
            jsSerializer.WriteObject(stream, obj); 

            return Encoding.UTF8.GetString(stream.ToArray()); 
        } 
        finally 
        { 
            stream.Close(); 
            stream.Dispose();
        } 
    } 
    public static T FromJson<T>(this string input) 
    { 
        MemoryStream stream = new MemoryStream();
        try {
            DataContractJsonSerializer jsSerializer = new DataContractJsonSerializer(typeof(T));
            stream = new MemoryStream(Encoding.UTF8.GetBytes(input)); 
            T obj = (T)jsSerializer.ReadObject(stream); return obj; 
        } 
        finally 
        { 
            stream.Close(); 
            stream.Dispose();
        }
    } 
}

[WebMethod]
public string callme()
{
    Dictionary<int, string> myObjects = new Dictionary<int, string>();
    myObjects.Add(1, "This");
    myObjects.Add(2, "is");
    myObjects.Add(3, "cool");
    string json = myObjects.ToJson();
    return json;
}

so Result is:

{"d":"[{\"Key\":1,\"Value\":\"This\"},{\"Key\":2,\"Value\":\"is\"},{\"Key\":3,\"Value\":\"cool\"}]"}

How I parse that in jquery? I m trying this but not help

$.ajax({
      type: "POST",
      url: "web.asmx/callme",
      data: "{}",
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      success: function(msg){
          $.each(msg.d, function (i) {
          $("#data2").append(i.Key + " " + i.Value + "<br/>");
        });
      }
    });

Upvotes: 1

Views: 15192

Answers (4)

marquito
marquito

Reputation: 895

The only way it worked for me was

var $nomeP = $("#<%= tbxBuscaJornalista.ClientID %>").val();

             $.ajax({
             url: "MyPage.asmx/MyMethod",
             dataType: "json",
             type: "POST",
             data: "{ 'variableName': '"+$nomeP+"' }",
             contentType: "application/json; charset=utf-8",
             success: function (msg) {
                 $.each(msg.d, function (index, value) {
                     $("#somePanel").append(index + " " + value + "<br/>");
                 });
             },
             error: function (XMLHttpRequest, textStatus, errorThrown) {
                 alert("Error: " + errorThrown + " XmlRequest: " + XMLHttpRequest);
             }
         });

Please notice the line data: "{ 'variableName': '"+$nomeP+"' }" which shows I had to enclose the variable name (same as expected in code-behind) and the value in single quotes. Otherwise it would not work. Also, I tried to iterate and use $(this).Key and $(this).Value but that wouldn't work either. I was forced to use the function (index, value) approach.

Upvotes: 1

Dinis Cruz
Dinis Cruz

Reputation: 4279

Based on JotaBe answer above, I created this extension method:

    public class KeyValue<TKey, TValue>
    {
        public TKey Key { get; set; }
        public TValue Value { get; set; }

        public KeyValue()
        {
        }       
    }
    public static class KeyValue_extensionMethods
    {
        public static List<KeyValue<TKey, TValue>> ConvertDictionary<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
        {
            var  keyValueList = new List<KeyValue<TKey, TValue>>();
            foreach (TKey key in dictionary.Keys)
                keyValueList.Add(new KeyValue<TKey, TValue> { Key = key, Value = dictionary[key] });
            return keyValueList;
        }
    }

Which then allows me to consume it using {object}.ConvertDictionary() syntax. For example:

[WebMethod(EnableSession = true)] [Admin(SecurityAction.Demand)]       
public List<KeyValue<Guid, string>>     Data_GuidanceItems_FileMappings()        
{
    return TM_Xml_Database.GuidanceItems_FileMappings.ConvertDictionary();
}

Upvotes: 1

JotaBe
JotaBe

Reputation: 39045

You'll have to do this things before it works:

  • put a ScriptService attribute to your web service
  • put a ScriptMethod attribute in your web service

If you do so, you don't even need to parse create the JSON in the server yourself. The WS infrastructure will do it for you.

Then, simply use msg.d on the client site. It will be automatically deserialized from the JSOn string.

Look here Using jQuery to Consume ASP.NET JSON Web Services for what you need to do on client side.

Here you have a full working sample with client and server side.

Be aware that before ASP.NET 3.5 the response message brought the data directly. In 3.5 and later, the data is in the .d property of the message.

EDIT2: Easier way to do it I made a mistake in the 1st edit: .asmx can't serialize a Dictionay as XML. So, when I tested the solution in the first edit via the .asmx page, I got an error. But JSON can serialize a Dictionary which has a string or an object as key.

So, you can use this class to convert your Dictionary<int,string> to Dictionary<string,string> using this generic class:

    public class DictionaryConverter
    {
        public static Dictionary<string,TValue> 
            ConvertDictionary<TKey,TValue>(Dictionary<TKey,TValue> dict)
        {
            Dictionary<string,TValue> newDict
                = new Dictionary<string, TValue>();
            foreach(TKey key in dict.Keys)
            {
                newDict.Add(key.ToString(), dict[key]);
            }
            return newDict;
        }
    }

This class can convert any Dictionary with any key type to a Dictionary<string,Tvalue> dictionary, which can be serialized as JSON, but not as XML. It uses the key type toString() method to convert the key in string. This will work perfectly for int and many other types. This method could be extended to receive a delegate to convert the key to string if necessary.

On client side you get the same thing with this solution and the one in the firs edit. The advantage of the one in the first edit is that it can also support serialization to XML: you can invoke the method through the .asmx page, and use the WebMethod as a regualr XML WebMethod.

EDIT: Serializing Dictionary<> in .asmx web service:

The serializer used with asmx doesn't support serializing dictionaries for XML. You can create a custom class and convert your dictionary to a list of this custom class, which has a key and a value property (the serializer doesn't support serializing KeyValuePair or Tuple, either, so you must use your own class).

This class serves two purposes:

  • It's a class that can be serialized with the serializer used by asmx for JSON
  • Allows to convert a dictionary in a list of elements of the class

    public class KeyValue<TKey, TValue>
    {
        public KeyValue()
        {
        }
    
        public TKey Key { get; set; }
        public TValue Value { get; set; }
    
        public static List<KeyValue<TKey,TValue>> ConvertDictionary
            (Dictionary<TKey,TValue> dictionary)
        {
            List<KeyValue<TKey, TValue>> newList
                = new List<KeyValue<TKey, TValue>>();
            foreach (TKey key in dictionary.Keys)
            {
                newList.Add(new KeyValue<TKey, TValue> 
                  { Key = key, Value = dictionary[key] });
            }
            return newList;
        }
    }
    

Your web method should look like this:

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)] // it's JSON by default
    public List<KeyValue<int,string>> GetKeyValueList()
    {
        List<KeyValue<int, string>> list
            = KeyValue<int,string>.ConvertDictionary(yourDictionary);
        return list;
    }

Notes:

  • you can use any method name instead of GetKeyValueList
  • the TKey, TValue must be the same types of your dictionary key and value.

On the client side you get an array of Objects with Key and Value properties, which can be accesed like this:

  msg.d[0].Key
  msg.d[0].Value

This is the jquery ajax call:

  $(document).ready(function () {
    $.ajax({
        url: 'MyService.asmx/GetKeyValueList',
        type: "POST",
        data: "{}",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        success: function (msg) {
            // use msg.d array of objects with Key and Value
        }
    });
  });

Upvotes: 3

Eli
Eli

Reputation: 17825

$.each(msg.d, function() {
    $("#data2").append(this.Key + " " + this.Value + "<br/>");
});

Also, it appears that your serialization is not working correctly, as the response coming back isn't being entirely parsed into JSON. The contents of d shouldn't be a string, it should be an object/array.

Upvotes: 2

Related Questions