Cómo analizar el tipo de diccionario con json-ajax

Tengo un diccionario que regresará del servidor, lo convertí al formato de cadena json como se muestra a continuación:

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;
}

entonces el resultado es:

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

¿Cómo analizo eso en jquery? Estoy intentando esto pero no ayuda

$.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/>");
        });
      }
    });

preguntado el 03 de mayo de 12 a las 15:05

4 Respuestas

Tendrás que hacer esto antes de que funcione:

  • Poner un ScriptService atribuir a su servicio web
  • Poner un ScriptMethod atributo en su servicio web

Si lo hace, ni siquiera necesita analizar y crear el JSON en el servidor usted mismo. La infraestructura de WS lo hará por usted.

Luego, simplemente use msg.d en el sitio del cliente. Se deserializará automáticamente de la cadena JSOn.

Mire aquí Uso de jQuery para consumir servicios web ASP.NET JSON para lo que necesita hacer en el lado del cliente.

Aquí tiene una muestra de trabajo completa con el lado del cliente y del servidor.

Tenga en cuenta que antes de ASP.NET 3.5, el mensaje de respuesta traía los datos directamente. En 3.5 y posteriores, los datos están en la propiedad .d del mensaje.

EDIT2: forma más fácil de hacerlo Cometí un error en la primera edición: .asmx no puede serializar un Dictionay como XML. Entonces, cuando probé la solución en la primera edición a través de la página .asmx, recibí un error. Pero JSON puede serializar un diccionario que tenga una cadena o un objeto como clave.

Entonces, puedes usar esta clase para convertir tu Dictionary<int,string> a Dictionary<string,string> usando esta clase genérica:

    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;
        }
    }

Esta clase puede convertir cualquier diccionario con cualquier tipo de clave en un Dictionary<string,Tvalue> diccionario, que se puede serializar como JSON, pero no como XML. Utiliza el tipo de clave toString() método para convertir la clave en cadena. Esto funcionará perfectamente para int y muchos otros tipos. Este método podría extenderse para recibir un delegado para convertir la clave en una cadena si es necesario.

En el lado del cliente, obtienes lo mismo con esta solución y la de la primera edición. La ventaja de la primera edición es que también puede admitir la serialización en XML: puede invocar el método a través de la página .asmx y usar WebMethod como un WebMethod XML regular.

EDITAR: Diccionario de serialización <> en el servicio web .asmx:

El serializador utilizado con asmx no admite la serialización de diccionarios. para XML. Puede crear una clase personalizada y convertir su diccionario en una lista de esta clase personalizada, que tiene una clave y una propiedad de valor (el serializador no admite la serialización KeyValuePair or Tuple, tampoco, por lo que debe usar su propia clase).

Esta clase tiene dos propósitos:

  • Es una clase que se puede serializar con el serializador que usa asmx para JSON
  • Permite convertir un diccionario en una lista de elementos de la clase

    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;
        }
    }
    

Su método web debería verse así:

    [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;
    }

Notas

  • puede usar cualquier nombre de método en lugar de GetKeyValueList
  • la TKey, TValue debe ser del mismo tipo que la clave y el valor de su diccionario.

En el lado del cliente, obtiene una matriz de Objetos con propiedades Clave y Valor, a los que se puede acceder de esta manera:

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

Esta es la llamada jquery ajax:

  $(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
        }
    });
  });

contestado el 05 de mayo de 12 a las 04:05

Luego, simplemente use msg.d en el sitio del cliente. Se deserializará automáticamente de la cadena JSOn. Entonces, ¿cómo en mi json? - Mustafa Ekici

Mire la muestra en "muestra de trabajo completa". Cambia los datos devueltos por el método web por un diccionario y verás que el .d La propiedad de la respuesta se puede usar directamente en el lado del cliente sin deserializarla. - JotaBe

hmm bien, gracias, de hecho, mi pregunta era de 2 partes, una de la solución proviene de usted y la otra de eli;) - Mustafa Ekici

@mekici: JotaBe mencionó esto, pero el quid de su problema es que está serializando manualmente el JSON en su método de servicio. Dado que ASP.NET lo hace automáticamente en este caso, terminará con datos doblemente serializados. Tengo una publicación dedicada a ese problema específico aquí: encosia.com/… - Dave Ward

Echa un vistazo a mi respuesta editada. @DaveWard a partir de .NET 4.0, el servicio asmx no puede realizar la serialización JSON de Dictionary, incluso si es . - JotaBe

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

Además, parece que su serialización no funciona correctamente, ya que la respuesta que regresa no se analiza por completo en JSON. Los contenidos de d no debería ser una cadena, debería ser un objeto/matriz.

contestado el 03 de mayo de 12 a las 15:05

Puedes hacer console.log(msg) y poner la respuesta de eso aquí? - Eli

jajaja. el último: Object { d="[{"Key":1,"Value":"This...Key":3,"Value":"cool"}]"} - Mustafa Ekici

Qué tal esto: console.log( typeof msg.d ); - Eli

Parece que su serialización no funciona correctamente, ya que la respuesta que regresa no se analiza por completo en JSON. Los contenidos de d no debería ser una cadena, debería ser un objeto/matriz. - Eli

usé el diccionario sin convertir la cadena jsong, por lo que msg.d regresa como objeto/matriz para que su respuesta no funcione. ¿qué piensas? - Mustafa Ekici

Basado en la respuesta anterior de JotaBe, creé este método de extensión:

    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;
        }
    }

Lo que luego me permite consumirlo usando {objeto}.ConvertDictionary() sintaxis. Por ejemplo:

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

Respondido el 16 de Septiembre de 12 a las 12:09

La única forma en que funcionó para mí fue

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);
             }
         });

Por favor, observe la línea data: "{ 'variableName': '"+$nomeP+"' }" lo que demuestra que tuve que encierre el nombre de la variable (igual que se esperaba en el código subyacente) y el valor entre comillas simples. De lo contrario, no funcionaría. Además, traté de iterar y usar $(this).Key y $(this).Value pero eso tampoco funcionaría. Me vi obligado a usar el function (index, value) enfoque.

Respondido el 05 de junio de 14 a las 20:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.