DataTable to Json utilisant jquery

J’essaie d’exécuter un service Web qui renvoie un DataTable avec le code suivant:

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

Si le service Web retourne une classe, alors cela fonctionne, donc cela n’a rien à voir avec les parameters d’entrée, etc. Il échoue uniquement lorsque la méthode Web renvoie un object datatable (l’élément datatable ne comporte que 2 colonnes et 2 lignes pour le test que je fais).

La classe WebService est décorée avec l’atsortingbut [ScriptService]. J’ai donc pensé qu’ASP.NET sérialiserait automatiquement la valeur de retour au format JSON. Cela ne semble pas fonctionner avec datatable.

La seule solution que j’ai trouvée consiste à renvoyer une chaîne (un object sérialisé JSON manuellement), mais il ne me semble pas correct de le faire de cette façon.
J’utilise Visual Studio 2008 avec .Net 3.5

En fin de compte, j’ai décidé d’utiliser la classe JavaScriptSerializer pour convertir le DataTable en chaîne JSON. Malheureusement, cette classe ne fonctionnant pas avec un DataTable, j’ai donc converti le DataTable en une liste de dictionnaires et passé cette liste à la classe JavaScriptSerializer. Cela ne prend que quelques lignes de code et cela fonctionne bien.
Exemple dans VB.net:

  Public Function GetJson(ByVal dt As DataTable) As Ssortingng Dim serializer As System.Web.Script.Serialization.JavaScriptSerializer = New System.Web.Script.Serialization.JavaScriptSerializer() Dim rows As New List(Of Dictionary(Of Ssortingng, Object)) Dim row As Dictionary(Of Ssortingng, Object) For Each dr As DataRow In dt.Rows row = New Dictionary(Of Ssortingng, 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 

Le moyen le plus simple consiste à utiliser les extensions LINQ to DataSet. Il faut d’abord créer une liste générique (SearchSerialResults n’est qu’un DTO dans ce cas) à partir du DataTable en utilisant LINQ to DataSet.

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

_returnedData est le DataTable dans ce cas. La deuxième étape consiste à effectuer la conversion. Dans ce cas, je retourne un object Json pour 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.ToSsortingng(), item.SearchItem, item.DeviceFound, item.Customer, item.ContractNumber, item.QuoteNumber, item.Country, item.City, item.BeginDate, item.EndDate, "" } }).ToArray() }; return Json(jsonObject) // for MVC 

Json.NET peut écrire des DataSets / DataTables au format JSON.

http://james.newtonking.com/archive/2008/09/06/dataset-datatable-serialization-with-json-net.aspx

Cela fonctionne très bien pour moi avec un WebService

  Imports System.Web.Script.Serialization Dim wsServicio As New ["YourWsInstance"] Dim dsInstEstado As New DataSet Dim sSql As Ssortingng sSql = " Your SQL Statement" dsInstEstado = wsServicio.getData("YourWebServiceParameters") Dim jsonSsortingng = DataTableToJSON(dsInstEstado.Tables("CA_INSTITUCION")) Return Json(jsonSsortingng, 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 Ssortingng, Object) For Each column In dt.Columns dict.Add(column.ColumnName, dt.Rows(i)(column)) Next arr(i) = dict Next Return arr End Function 

Je dois avouer que je ne suis pas très surpris – DataTable enfreint la plupart des règles des données structurées. Pourquoi ne pas simplement projeter de la table de données dans un object typé? Une question connexe a déjà été posée … ou si vous connaissez le schéma du DataTable simplement la conversion en C # …

Construire manuellement le JSON peut marcher, mais il y a beaucoup de cas à éviter. Pour être honnête, je préférerais laisser un cadre existant le gérer.

.Net 3.5 a un JSONSerializer qui devrait être capable de gérer un datatable. Vous voudrez peut-être revoir votre code de service et essayer de le faire utiliser. En outre, j’ai mis du code ensemble pour le faire manuellement dans cette question.

Comme Marc, je ne suis pas non plus surpris que le DataTable rompt votre échange webservice / json. J’aimerais également appuyer Json.NET.

Mais si vous décidez de ne pas y aller, vous n’avez toujours pas à construire le JSON manuellement. Créez simplement votre propre classe personnalisée lean avec toutes les propriétés dont vous avez besoin, puis renvoyez un tableau de cette classe. Vous devrez bien sûr écrire du code pour “convertir” votre table de données dans votre nouvelle classe. Je sais, cela pourrait être beaucoup de code écrit, mais c’est beaucoup moins sujet aux erreurs que d’essayer de créer manuellement une chaîne json.

J’ai trouvé cette classe C # très utile:

 [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 m_rows; public IList 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 ssortingng id; public ssortingng[] cell; }