convert from SqlDataReader to JSON

public string toJSON(SqlDataReader o)
{
    StringBuilder s = new StringBuilder();
    s.Append("[");
    if (o.HasRows)
        while (o.Read())
            s.Append("{" + '"' + "Id" + '"' + ":" + o["Id"] + ", "
            + '"' + "CN" + '"' + ":" + o["CatName"] + ", "
            + '"' + "Ord" + '"' + ":" + o["Ord"] + ","
            + '"' + "Icon" + '"' + ":" + o["Icon"] + "}, ");
    s.Remove(s.Length - 2, 2);
    s.Append("]");
    o.Close();
    return s.ToString();
}

I'm using here my own function to do serialization . I need to know if this is a good way or I should use another . BTW I've tried to use the JavaScriptSerializer but this didn't work with SqlDataReader . thanx


Solution 1:

If you want something that'll convert to arbitrary JSON, you could convert by serializing it into a Dictionary(Of string, object) thusly:

public IEnumerable<Dictionary<string, object>> Serialize(SqlDataReader reader)
{
    var results = new List<Dictionary<string, object>>();
    var cols = new List<string>();
    for (var i = 0; i < reader.FieldCount; i++) 
        cols.Add(reader.GetName(i));

    while (reader.Read()) 
        results.Add(SerializeRow(cols, reader));

    return results;
}
private Dictionary<string, object> SerializeRow(IEnumerable<string> cols, 
                                                SqlDataReader reader) {
    var result = new Dictionary<string, object>();
    foreach (var col in cols) 
        result.Add(col, reader[col]);
    return result;
}

And then use the NewtonSoft.Json JsonConvert object to get your JSON:

var r = Serialize(reader);
string json = JsonConvert.SerializeObject(r, Formatting.Indented);

UPDATE: If you just want to use built-in methods, and you happen to be using MVC, you can use the built in Json helper method on your newly serialized :

JsonResult Index(int id) {
    var r = Serialize(reader);
    return Json(r, JsonRequestBehavior.AllowGet);
}

Solution 2:

This should do the job

private String sqlDatoToJson(SqlDataReader dataReader)
{
    var dataTable = new DataTable();
    dataTable.Load(dataReader);
    string JSONString = string.Empty;
    JSONString = JsonConvert.SerializeObject(dataTable);
    return JSONString;
}

Solution 3:

I encounter use cases where the number of rows being returned by the data reader may become problematic with respect to memory consumption. The following code uses a JsonWriter (from JSON.NET) over a stream. One can certainly debate the utility of enormous JSON documents, but sometimes our use cases are dictated by others :-)

A few notes:

  • My SqlDataReader may contain multiple result sets ('tables')
  • I may be sending the output to a FileStream or an HttpResponse stream
  • I've 'abstracted' my object names to match the first column returned per result set
  • Because of the potential for large result sets, I use async methods of the SqlDataReader.
  • I'm letting JSON.NET handle all the serialization issue of the actual data contained in the data reader results.

The code:

var stream = ... // In my case, a FileStream or HttpResponse stream
using (var writer = new JsonTextWriter(new StreamWriter(stream)))
{
    writer.WriteStartObject();  
    do
    {
        int row = 0;
        string firstColumn = null;
        while (await reader.ReadAsync())
        {
            if (row++ == 0)
            {
                firstColumn = reader.GetName(0);
                writer.WritePropertyName(string.Format("{0}Collection", firstColumn));
                writer.WriteStartArray();   
            }
            writer.WriteStartObject();
            for (int i = 0; i < reader.FieldCount; i++)
            {
                if (!reader.IsDBNull(i)) { 
                    writer.WritePropertyName(reader.GetName(i));
                    writer.WriteValue(reader.GetValue(i));
                }
            }
            writer.WriteEndObject(); 
        }
        writer.WriteEndArray();
    } while (await reader.NextResultAsync());

    writer.WriteEndObject();
}

An example of heterogeneous output would be:

{
    "ContactCollection": {
        "ContactItem": [{
                "ContactID": "1",
                "Contact": "Testing",
            },
            {
                "ContactID": "2",
                "Contact": "Smith, John",
            },
            {
                "ContactID": "4",
                "Contact": "Smith, Jane",
            }
        ],
        "MessageItem": [{
                "MessageID": "56563",
                "Message": "Contract Review Changed",
            },
            {
                "MessageID": "56564",
                "Message": " Changed",
            },
            {
                "MessageID": "56565",
                "Message": "Contract Review - Estimated Completion Added.",
            }
        ]
    }
}

Reference:

  • http://www.newtonsoft.com/json/help/html/Performance.htm

Solution 4:

Another option would be to use James Newton-King's excellent JSON.NET library - http://www.newtonsoft.com/json

Here's a quick example on how to use it to build up a collection and then output it as a JSON-serialized string:

using Newtonsoft.Json;

class Program
{
    static void Main(string[] args)
    {
        ArrayList objs = new ArrayList();

        //get the data reader, etc.
        while(o.Read())
        {
            objs.Add(new
            {
                Id = o["Id"],
                CN = o["CatName"],
                Ord = o["Ord"],
                Icon = o["Icon"]
            });
        }

        //clean up datareader

        Console.WriteLine(JsonConvert.SerializeObject(objs));
        Console.ReadLine();
    }
}

You could do the same with your looping by reading in each row of your SqlDataReader into an anonymous object and then use JSON.NET to serialize it to a string.

Hope this helps!