views:

7606

answers:

8

I'm trying to execute a web service which returns a DataTable with the following piece of code:

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

If the webservice returns a class then it works so it has nothing to do with the input paramters etc. It only fails when the web method returns a datatable (the datatable only has 2 columns and 2 rows for the test I'm doing). The WebService class is decorated with the [ScriptService] attribute so I thought that ASP.NET would automatically serialize the return value as JSON. It doesn't seem to work with datatable. The only solution I've found was to return a string (a manually JSON serialized object) but it doesn't seem right to me to do it this way.
I'm using Visual Studio 2008 with .Net 3.5

Thanks.

+1  A: 

I must admit I'm not hugely surprised - DataTable basically breaks most of the rules of structured data. Why not simply project from the data-table into a typed object? A related question came up earlier... or if you know the schema of the DataTable just do the conversion in C#...

Manually building the JSON might work, but there are a lot of edge-cases to avoid; I'd rather let an existing framework handle it, to be honest.

Marc Gravell
A: 

.Net 3.5 has a JSONSerializer that should be able to handle a datatable. You may want to look at your service code again and try getting it to use that. Also, I put some code together to do it manually in this question.

Joel Coehoorn
+1  A: 

Json.NET has the ability to write DataSets/DataTables to JSON.

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

James Newton-King
A: 

Like Marc, I too am not surprised that the DataTable breaks your webservice/json exchange. I'd like to endorse Json.NET also.

But if you decide to not go with it, you still don't have to build the json manually. Just make your own lean custom class with all the properties you need and then return an array of that class. You will of course have to write code to "convert" your data table into your new class. I know, it could be a lot of code writing, but it's a lot less error prone then trying to manually make a json string.

Al W
A: 

In the end, I've decided to use the JavaScriptSerializer class to convert the DataTable into a JSON string. Unfortunately, this class doesn't work with a DataTable so I converted the DataTable into a list of dictionnaries and pass that list to the JavaScriptSerializer class. It takes only a few lines of code and it works fine.
Example in 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
Anthony
A: 

Have a look at this: post

Kyryll
A: 

Easiest way is to use the LINQ to DataSet extensions. First need to create a generic list (SearchSerialResults is just a DTO in this case) from the DataTable using 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 is the DataTable in this case. Step 2 is to do the conversion. In this case, I am returning a Json object for a 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
john