2009-02-13 54 views
5

Estoy intentando ejecutar un servicio web que devuelve un DataTable con el siguiente fragmento de código:DataTable a JSON usando jQuery

$.ajax({ 
    type: "POST", 
    url: url, 
    data: data, 
    contentType: "application/json; charset=utf-8", 
    dataType: "json", 
    success: function(msg) { 
     //do things 
     } 
    }); 

Si el servicio web devuelve una clase entonces funciona por lo que no tiene nada que ver con los parámetros de entrada, etc. Solo falla cuando el método web devuelve una tabla de datos (la tabla de datos solo tiene 2 columnas y 2 filas para la prueba que estoy haciendo).

La clase WebService está decorada con el atributo [ScriptService] así que pensé que ASP.NET serializaría automáticamente el valor de retorno como JSON. No parece funcionar con datatable.

La única solución que encontré fue devolver una cadena (un objeto serializado JSON manualmente) pero no me parece correcto hacerlo de esta forma.
Estoy usando Visual Studio 2008 con .Net 3.5

Respuesta

8

Al final, he decidido utilizar la clase JavaScriptSerializer para convertir la DataTable en una cadena JSON. Desafortunadamente, esta clase no funciona con una DataTable, así que convertí la DataTable en una lista de dictionnaries y pasé esa lista a la clase JavaScriptSerializer. Solo requiere unas pocas líneas de código y funciona bien.
Ejemplo en VB.net:

Public Function GetJson(ByVal dt As DataTable) As String 

     Dim serializer As System.Web.Script.Serialization.JavaScriptSerializer = New System.Web.Script.Serialization.JavaScriptSerializer() 
     Dim rows As New List(Of Dictionary(Of String, Object)) 
     Dim row As Dictionary(Of String, Object) 

     For Each dr As DataRow In dt.Rows 
      row = New Dictionary(Of String, Object) 
      For Each col As DataColumn In dt.Columns 
       row.Add(col.ColumnName, dr(col)) 
      Next 
      rows.Add(row) 
     Next 
     Return serializer.Serialize(rows) 
    End Function 
1

Debo admitir que no estoy muy sorprendido - DataTable básicamente rompe la mayoría de las reglas de datos estructurados. ¿Por qué no simplemente proyectar desde la tabla de datos a un objeto tipado? A related question apareció más temprano ... o si conoce el esquema de DataTable simplemente realice la conversión en C# ...

La construcción manual de JSON podría funcionar, pero hay muchos casos extremos que debe evitar; Prefiero dejar que un marco existente lo maneje, para ser honesto.

0

.Net 3.5 tiene un JSONSerializer que debería poder manejar una tabla de datos. Es posible que desee revisar su código de servicio nuevamente e intentar que lo use. Además, puse un código para hacerlo manualmente en this question.

0

como Marc, yo también no me sorprende que el DataTable rompe el intercambio de servicio web/JSON. Me gustaría respaldar a Json.NET también.

Pero si decides no seguir adelante, todavía no tienes que compilar el json manualmente. Simplemente haga su propia clase personalizada con todas las propiedades que necesita y luego devuelva una matriz de esa clase. Por supuesto, tendrá que escribir un código para "convertir" su tabla de datos en su nueva clase. Lo sé, podría ser una gran cantidad de escritura de código, pero es mucho menos propenso a errores y luego tratar de hacer manualmente una cadena json.

5

La manera más fácil es utilizar el LINQ a las extensiones de conjunto de datos. Primero necesita crear una lista genérica (SearchSerialResults es solo una DTO en este caso) desde DataTable usando LINQ to DataSet.

  var resultItems = (from DataRow dr in _returnedData.AsEnumerable() 
          select new SearchSerialResults 
          { 
           ContractLineItem = (int)dr["fldContractLineItemID"], 
           SearchItem = (string)dr["Search Item"], 
           Customer = (string)dr["Customer"], 
           DeviceFound = (string)dr["Device Found"], 
           Country = (string)dr["Country"], 
           City = (string)dr["City"], 
           ContractNumber = (string)dr["Contract Number"], 
           QuoteNumber = (string)dr["Quote Number"], 
           BeginDate = (string)dr["Begin Date"], 
           EndDate = (string)dr["End Date"] 
          }).ToList(); 

_returnedData es la DataTable en este caso. El paso 2 es hacer la conversión. En este caso, estoy devolviendo un objeto Json para un jqGrid.

var jsonObject = new 
     { 
      total = totalPages, 
      pageSize, 
      records = totalRecords, 
      rows = (from SearchSerialResults item in resultItems 
        select new 
        { 
         id = item.ContractLineItem, 
         cell = new[] 
         { 
          item.ContractLineItem.ToString(), 
          item.SearchItem, 
          item.DeviceFound, 
          item.Customer, 
          item.ContractNumber, 
          item.QuoteNumber, 
          item.Country, 
          item.City, 
          item.BeginDate, 
          item.EndDate, 
          "" 
         } 
        }).ToArray() 
     }; 
return Json(jsonObject) // for MVC 
+1

Creo que su respuesta es la mejor. –

+0

Ídem. Usa LINQ y toma lo que necesites. Mucho más fácil que alternar manualmente los resultados. –

+0

Gran respuesta. Uno de esos momentos 'duh' en los que no puedo creer que tenga que buscar esto. –

0

Me encontraron esta clase C# muy útil:

[Serializable] 
public class TableMethod 
{ 
    private int m_total; public int total { get { return this.m_total; } set { this.m_total = value; } } 
    private int m_page; public int page { get { return this.m_page; } set { this.m_page = value; } } 
    private int m_records; public int records { get { return this.m_records; } set { this.m_records = value; } } 
    private IList<RowElement> m_rows; public IList<RowElement> rows { get { return this.m_rows; } set { this.m_rows = value; } } 
    public TableMethod() 
    { 
     this.m_records = 20; 
     this.m_total = 20; 
     this.m_page = 1; 
    } 
} 
[Serializable] 
public class RowElement 
{ 
    public string id; 
    public string[] cell; 
} 
+1

Alguna explicación hubiera sido útil aquí. –

2

Funciona para muy bien para mí con un servicio web

Imports System.Web.Script.Serialization 

    Dim wsServicio As New ["YourWsInstance"] 
    Dim dsInstEstado As New DataSet 
    Dim sSql As String 

    sSql = " Your SQL Statement" 
    dsInstEstado = wsServicio.getData("YourWebServiceParameters") 
    Dim jsonString = DataTableToJSON(dsInstEstado.Tables("CA_INSTITUCION")) 
    Return Json(jsonString, JsonRequestBehavior.AllowGet) 

    Function DataTableToJSon(dt As DataTable) As Object 
    Dim arr(dt.Rows.Count - 1) As Object 
    Dim column As DataColumn 
    For i = 0 To dt.Rows.Count - 1 
     Dim dict As New Dictionary(Of String, Object) 
     For Each column In dt.Columns 
      dict.Add(column.ColumnName, dt.Rows(i)(column)) 
     Next 
     arr(i) = dict 
    Next 
    Return arr 
End Function