I am executing a stored procedure on my server which returns a DataTable. The DataTable has some columns that have JSON data in them. When I return the result to the client the top-level of the DataTable is properly formatted to JSON but the columns with JSON data are returned as strings. How can I convert the entire table (including columns with JSON) to JSON before returning to the client?
DataTable
ColA ColB ColC
1 Test [{"ColD":2,"ColE":"Another Test"}]
What I'm Getting
[
{
"ColA": 1,
"ColB": "Test",
"ColC": "[{\"ColD\":2,\"ColE\":\"Another Test\"}]"
}
]
What I Need
[
{
"ColA": 1,
"ColB": "Test",
"ColC": [
{
"ColD": 2,
"ColE": "Another Test"
}
]
}
]
I had a breakthrough after posting the question. I created an extension method for the DataTable that would convert the DataTable to a List<Dictionary<string, object>>. In the process I check for values that start with [ or { and deserialize them using JsonConvert.DeserializeObject.
public static List<Dictionary<string, object>> ToJson(this DataTable dt)
{
var list = new List<Dictionary<string, object>>();
foreach (DataRow row in dt.Rows)
{
var dict = new Dictionary<string, object>();
foreach (DataColumn col in dt.Columns)
{
if (row[col].ToString().StartsWith('{') || row[col].ToString().StartsWith('['))
{
dict[col.ColumnName] = JsonConvert.DeserializeObject(row[col].ToString());
}
else
{
dict[col.ColumnName] = row[col];
}
}
list.Add(dict);
}
return list;
}
Related
I want JSON data in this format. And itemlist data is coming from itemlist table and remaining are from another table .itemlist is the 2nd table name.
JSON
{
\"supplyType\":\"O\",
\"subSupplyType\":\"1\",
\"subSupplyDesc\":\"\",
\"docType\":\"INV\",
\"docNo\":\"107500F18TO0045\",
\"docDate\":\"15/10/2017\",
\"fromGstin\":\"03EHFPS5910D3A1\",
\"fromTrdName\":\"Diwa\",
\"fromAddr1\":\"2ND CROSS NO 59 19 \",
\"fromAddr2\":\"GROUND FLOOR OSBORNE ROAD \",
\"fromPlace\":\"BANGALORE\",
\"fromPincode\":560042,
\"actFromStateCode\":29,
\"fromStateCode\":29,
\"toGstin\":\"02EHFPS10D2Z0\",
\"toTrdName\":\"sthuthya\",
\"toAddr1\":\"Shree Nilaya\",
\"toAddr2\":\"Dasarahosahalli\",
\"toPlace\":\"Beml Nagar\",
\"toPincode\":400013,
\"actToStateCode\":9,
\"toStateCode\":27,
\"transactionType\":4,
\"dispatchFromGSTIN\":\"29AAAAA1303P1ZV\",
\"dispatchFromTradeName\":\"xyz Traders\",
\"shipToGSTIN\":\"03EHFPS5910D3A1\",
\"shipToTradeName\":\"XYZ Traders\",
\"otherValue\":-100,
\"totalValue\":100,
\"cgstValue\":0,
\"sgstValue\":0,
\"igstValue\":300.67,
\"cessValue\":400.56,
\"cessNonAdvolValue\":400,
\"totInvValue\":68358,
\"transporterId\":\"\",
\"transporterName\":\"\",
\"transDocNo\":\"\",
\"transMode\":\"1\",
\"transDistance\":\"656\",
\"transDocDate\":\"\",
\"vehicleNo\":\"PVC1234\",
\"vehicleType\":\"R\",
\"itemList\":[
{
\"productName\":\"rice\",
\"productDesc\":\"Wheat\",
\"hsnCode\":1001,
\"quantity\":4,
\"qtyUnit\":\"BOX\",
\"cgstRate\":0,
\"sgstRate\":0,
\"igstRate\":3,
\"cessRate\":0,
\"cessNonAdvol\":0,
\"taxableAmount\":56099
}
]
}";
//
Dictionary<string, object> rows = new Dictionary<string, object>();
Dictionary<string, object> rowelement;
[System.Web.Http.HttpGet]
public JsonResult Show()
{
JavaScriptSerializer serial1 = new JavaScriptSerializer();
Registration obj = new Registration();
DataTable dt = new DataTable();
dt = obj.employeedetails();
if (dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
rowelement = new Dictionary<string, object>();
foreach (DataColumn col in dt.Columns)
{
rowelement.Add(col.ColumnName, dr[col]);
}
rows.Add("",rowelement);
}
}
return Json(rows, JsonRequestBehavior.AllowGet);
This is just an approach. not a complete solution.
You can create a new class, fill the data coming from DB in it, serialize it using JSON library.
I am trying to export a number of datasets to Excel in an Angular 6 application. For that I am using XLSX and File-save as given in this ex:
https://medium.com/#madhavmahesh/exporting-an-excel-file-in-angular-927756ac9857
The problem is that the fields might keep changing time to time, so I need somthing dynamic (do not want to specify column names). For that I found a very good example:
Binding Json data to a table in mvc 4
However, I am not getting the data in the right format. I need something like array of array.
I am assuming the return type should be async Task<JsonResult> in that case but not sure how to make it work.
I am attaching two images - of the result I am getting
and the intended result
Here is code from the sample cited. The stored proc call to GetMyData, uses SqlAdapter and there is no need to specify field names
public JsonResult GetValue()
{
JsonResult json = new JsonResult();
DataSet ds = GetMyData();
/*LoadDoctordetailsNew is method where i get data from database and convert
to dataset.It returns a dataset*/
string returnData = GetJson(ds.Tables[0]);
json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
json.Data = returnData;
return json;
}
public static string GetJson(DataTable dt)
{
System.Web.Script.Serialization.JavaScriptSerializer serializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
List<Dictionary<string, object>> rows =
new List<Dictionary<string, object>>();
Dictionary<string, object> row = null;
foreach (DataRow dr in dt.Rows)
{
row = new Dictionary<string, object>();
foreach (DataColumn col in dt.Columns)
{
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
return serializer.Serialize(rows);
}
public static DataSet GetMyData()
{
try
{
using (SqlConnection connection = Connection.GetConnection())
{
SqlDataAdapter da = new SqlDataAdapter("dbo.MySQLStoredproc", connection);
da.SelectCommand.CommandType = CommandType.StoredProcedure;
DataSet ds = new DataSet();
da.Fill(ds);
return ds;
}
}
catch (Exception ex)
{
throw;
}
}
Please guide!
P.S.
This technique is using Dapper. It returns data as desired (Array of Array) format, but in the Object we have to specify column names which will be hard coding and therefore, I can't use
public static IEnumerable<Object> GetMyData()
{
var strQuery = #"[dbo].[Myproc]";
IEnumerable< Object > items = new List<Object>(0);
var p = new DynamicParameters();
using (SqlConnection con = Connection.GetConnection())
{
items = con.Query<Object>(strQuery, param: p, commandTimeout: 120, commandType: System.Data.CommandType.StoredProcedure);
}
return items;
}
Call from MVC Controller
[HttpPost]
public async Task<JsonResult> SelectMyData()
{
var task = Task.Run(() => Request.GetMyData());
var retData = await task;
return new JsonResult
{
ContentType = "application/json",
Data = retData,
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
MaxJsonLength = int.MaxValue
};
}
You should return the List<Dictionary<string, object>> instead of string. You don't need to Serialize the data it will be take care by JsonResult
public JsonResult GetValue()
{
JsonResult json = new JsonResult();
DataSet ds = GetMyData();
/*LoadDoctordetailsNew is method where i get data from database and convert
to dataset.It returns a dataset*/
json.Data = GetJson(ds.Tables[0]);
json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return json;
}
public static List<Dictionary<string, object>> GetJson(DataTable dt)
{
List<Dictionary<string, object>> rows =
new List<Dictionary<string, object>>();
Dictionary<string, object> row = null;
foreach (DataRow dr in dt.Rows)
{
row = new Dictionary<string, object>();
foreach (DataColumn col in dt.Columns)
{
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
return rows;
}
Well I got a JSON String after decrypting which looks like
"{\"HardwareInformation\":{\"NumberOfProcessors\":8,\"PageSize\":4096,\"ProcessorType\":586,\"ProcessorTypeText\":\"]\",\"ActiveProcessorMask\":255},\"SystemInformation\":{\"ComputerName\":\"PD-AT-23006\",\"UserName\":\"230010\",\"SystemDirectory\":\"C:\\\\\\\\Windows\\\\\\\\system32\",\"WindowsDirectory\":\"C:\\\\\\\\Windows\",\"Is64BitWindows\":1},\"EnvironmentVariables\":{\"OS\":\"Windows_NT\",\"PATH\":\"C:\\\\\\\\Program Files (x86)\\\\\\\\NVIDIA Corporation\\\\\\\\PhysX\\\\\\\\Common;C:\\\\\\\\Program Files (x86)\\\\\\\\Intel\\\\\\\\iCLS Client\\\\\\\\;C:\\\\\\\\Program Files\\\\\\\\Intel\\\\\\\\iCLS Client\\\\\\\\;C:\\\\\\\\Windows\\\\\\\\system32;C:\\\\\\\\Windows;C:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\Wbem;C:\\\\\\\\Windows\\\\\\\\System32\\\\\\\\WindowsPowerShell\\\\\\\\v1.0\\\\\\\\;C:\\\\\\\\Program Files\\\\\\\\Intel\\\\\\\\Intel(R) Management Engine Components\\\\\\\\DAL;C:\\\\\\\\Program Files\\\\\\\\Intel\\\\\\\\Intel(R) Management Engine Components\\\\\\\\IPT;C:\\\\\\\\Program Files (x86)\\\\\\\\Intel\\\\\\\\Intel(R) Management Engine Components\\\\\\\\DAL;C:\\\\\\\\Program Files (x86)\\\\\\\\Intel\\\\\\\\Intel(R) Management Engine Components\\\\\\\\IPT\",\"HOMEPATH\":\"\\\\\\\\\",\"TEMP\":\"C:\\\\\\\\Users\\\\\\\\230010\\\\\\\\AppData\\\\\\\\Local\\\\\\\\Temp\"}}\0"
The formatted JSON String is
{
"HardwareInformation": {
"NumberOfProcessors": 8,
"PageSize": 4096,
"ProcessorType": 586,
"ProcessorTypeText": "]",
"ActiveProcessorMask": 255
},
"SystemInformation": {
"ComputerName": "PD-AT-23006",
"UserName": "230010",
"SystemDirectory": "C:\\\\Windows\\\\system32",
"WindowsDirectory": "C:\\\\Windows",
"Is64BitWindows": 1
},
"EnvironmentVariables": {
"OS": "Windows_NT",
"PATH": "C:\\\\Program Files (x86)\\\\NVIDIACorporation\\\\PhysX\\\\Common;
..............................and more
Well, now I want to set the head information like "HardwareInformation", "SystemInformation" and "EnvironmentVariables" as a column and under them in a row the other information.
Because there could always come some new columns or rows, it's important that the code is working independently from me (Like not adding a new class just for the data)
I've tried using Newtonsoft.JSON and got the JSON in dynamic
dynamic json = Crypt.getEncodedTXT("37MpQhzhSCGuReZnHZblzk+TJnD0uYkTbcoo0JvpV/bMeLFuckuVxYzbZlKOrfAqtwHOeaSFzGIRZybjgFVaz7BISjxEg5wTlZch788Bm4nMegha0rNYpaYXCliZ50MTimxxin0ch3CDIHVQTN1U7oxDgA2gt+2+5ceQnhKMpY5YOQFev44HCdpNVb03AO+HT9F0MtlUsIG84wg/Ez3i1Ab9+HV/Hs26hhbIoJEdGxh+6OP6c0/bp3NuloCmuC5rFb010KxSBxmNcFhmU59HYfDJv/W7gnfKhEaP6doQ9di5ou3GQNehy+LGGxK/2HqTayfurqtjJ9OT9TIZ0nJSH25C2VAvLPqG12WA/8qZgmbDscy6WZsW/LA5xbHN3j2bIo3s8xjMQyvDtvEoXBB7/XK3JsWkIk5xNYTCPuzkZEg8hh3jcrsEmitAhyITBtBmsNm2foyL8oMhO1fw4efj4oEYyQKSZJEoMANamKPdrIHbGpQDnm4Yn+aOVsBI2i980t5SlO9WNZ0vh4h4lPtmxLKSS6YMqu/14qpDpVgytBoK1aRFKRIxdPo/su8uO7R2m1VFgmWH4cE2Vk0kLNORi6gPmqkhunbPHZwN/qWiU2v6Lu3VjQ3RbkSayI+JzBw7IF+GDVNN5Sw3HS5uPpVGxPNLZTQ2V1xJ+zQB+A79Ps1lX1zLh8cbmgbT7CDBjhJQ6TNCU0UeLuSoCQOJVoRPyhY7ZmNINHLaJk4wboVg3D2vASr2P6/XOeOtWsjyjjD6SxW+qeUqaRvSAAJ3XlvYMTn0wbGjl/CNymLV28dUnWJHlM+HbgZjrvV7psb8I83B+O1wRBQwbMtuwBy7zsFWfErqscADwTCuksbRJuRfOQFRX/JI0FewRJtHZh6XDQ5QACOLkUUdQAo/Nhb8jhpnMQn5j5UOsO97lfVOmFp0MGovxyNLdjTefDnptForKmhkgDdcel8dpM82UUieBJG4igoSf+qRbhmihdutHB3lP7B0barxc4+t1As+wollx0EXSIBCAZtSmwHaaVVn/ZcxI36dIAoSjb5EIHO18JfWnm0Q/dwwYkUm4Xr/2thdtJeL9icmIDn+3bmo76jXu6gdUbhsUYZRBOOOsfmhL6dJMDMM5q/s0d2scaA+22XnnfiebDhet7i8xQe1DfnAME4qjlL1gBTqSPDKG/XZ2pnH5EpVbn+l32Oj2WD2YWem9TKPZoOJ6j3CwYfm0M0A1Z1FsoXtHrfXw535tOTVbn9ThrJhSMA88OaG10Huvi/A2MzeuaiisIfPwXiWZm8wa0mveR/hD1I5I7y+0/qEoavXDhwmpIytPJTIdg6gEHr7nsqoGNTKCg4ZBBMqKbIucV7PDSznus4zAt0McVN1dVt92k/pUOgmeW7SshYZhsrGrUz8Z9lDXdWNumgoX1iSIuDpCQ==");
(Please ignore the decrypt) and as a JObject
JObject json1 = JObject.Parse(json);
The dynamic is not formatted and the JObject is.
The table should look like this:
Thanks for your help.
First, deserialize the json into Dictionary<string, Dictionary<string, object>>. Count number of rows and columns. Add columns and Rows.
string jstr = "{\"HardwareInformation\": {\"NumberOfProcessors\": 8,\"PageSize\": 4096,\"ProcessorType\": 586,\"ProcessorTypeText\": \"]\",\"ActiveProcessorMask\": 255},\"SystemInformation\": {\"ComputerName\": \"PD-AT-23006\",\"UserName\": \"230010\",\"SystemDirectory\": \"C:\\\\Windows\\\\system32\",\"WindowsDirectory\": \"C:\\\\Windows\",\"Is64BitWindows\": 1},\"EnvironmentVariables\": {\"OS\": \"Windows_NT\",\"PATH\": \"C:\\\\Program Files (x86)\\\\NVIDIACorporation\\\\PhysX\\\\Common\"}}";
var info = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, object>>>(jstr);
DataTable dt = new DataTable();
var Maxcolumn = info.Count;
var maxRows = info.Select(x => x.Value.Count).Max();
// Add Columns
foreach (var column in info)
dt.Columns.Add(new DataColumn(column.Key, typeof(string)));
// Add Rows
for (int r = 0; r < maxRows; r++)
{
DataRow newrow = dt.NewRow();
for (int c = 0; c < Maxcolumn; c++)
{
var columnDic = info.Values.ElementAt(c);
var key = r < columnDic.Count ? columnDic.Keys.ElementAt(r) : "";
var value = r < columnDic.Count ? columnDic.Values.ElementAt(r).ToString() : "";
newrow[c] = key + ": " + value;
}
dt.Rows.Add(newrow);
}
Then bind the DataTable to your DataGridView
dataGridView1.DataSource = dt;
Output:
I have the following JSON which I need to manipulate into a different JSON format to be consumed by another process. My data is variable to some extent. Here is an example:
{
"subform_12": {
"multiline_2": "Subform 1 Long Text",
"listpicker_5": "High",
"alpha_1": "SubForm 1 Text"
},
"subform_13": {
"multiline_2": "Subform 2 Long Text",
"alpha_1": "SubForm 2 Text"
}
}
The variable part is the name of the json object (eg "subform_13") and the number and content of name pairs per object (eg "multiline_2": "Subform 1 Long Text").
What I need to do is convert each node into its own chunk of json, as in the following format:
{
"subform_13": [
[{
"fieldKey": "multiline_2",
"value": "Subform 2 Long Text"
},
{
"fieldKey": "alpha_1",
"value": "SubForm 2 Text"
}
]
]
}
Then separately:
{
"subform_13": [
[{
"fieldKey": "multiline_2",
"value": "Subform 2 Long Text"
},
{
"fieldKey": "alpha_1",
"value": "SubForm 2 Text"
}
]
]
}
So far I see that I can iterate thru the list as follows:
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(
jsonString,
new Newtonsoft.Json.JsonSerializerSettings()
{
DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
});
foreach (var item in json)
{
// I can see the "subform_13" and contents here in item , how do I generically extract them?
}
Any help appreciated.
Here is your Main method augmented with the ability to iterate through all values:
static void Main(string[] args)
{
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string,JObject>>(
jsonString,
new Newtonsoft.Json.JsonSerializerSettings()
{
DateParseHandling = Newtonsoft.Json.DateParseHandling.None,
});
foreach (var item in json)
{
var key = item.Key; // "subform_12"
var val = item.Value;
Console.WriteLine(key+":");
foreach (var field in val)
{
var fieldKey = field.Key; // e.g. "multiline_2"
var fieldVal = field.Value; // e.g. "Subform 1 Long Text"
Console.WriteLine($"{fieldKey}={fieldVal.Value<string>()}");
}
Console.WriteLine();
}
}
I am just printing the values out; you would construct your new objects - for example as dynamic - using these values.
The output of my Main is:
subform_12:
multiline_2=Subform 1 Long Text
listpicker_5=High
alpha_1=SubForm 1 Text
subform_13:
multiline_2=Subform 2 Long Text
alpha_1=SubForm 2 Text
Hope it helps.
There are probably more elegant ways using linq, but here's code using a plain old JavaScriptSerializer from System.Web.Extensions.
There is a result dictionary, which you probably don't need if you want each object separated.
The json strings for each object is stored in the allJson list.
Similary, if you want the dictionary objects themselves you could just add seperated to a list during each iteration.
string s = "{\"subform_12\":{\"multiline_2\":\"Subform 1 Long Text\",\"listpicker_5\":\"High\",\"alpha_1\":\"SubForm 1 Text\"},\"subform_13\":{\"multiline_2\":\"Subform 2 Long Text\",\"alpha_1\":\"SubForm 2 Text\"}}";
JavaScriptSerializer ser = new JavaScriptSerializer();
Dictionary<string, object> obj = ser.DeserializeObject(s) as Dictionary<string, object>;
// combined dictionary of all results
Dictionary<string, object> result = new Dictionary<string, object>();
// an intermediary dictionary to house the results of each object
Dictionary<string, object> separated = new Dictionary<string, object>();
// a list to hold the json representation of each separate object
List<String> allJson = new List<string>();
foreach (KeyValuePair<string, object> src in obj)
{
Dictionary<string, object> children = (Dictionary<string, object>)src.Value;
Dictionary<string, object> t = new Dictionary<string, object>();
separated = new Dictionary<string, object>();
List<object> l = new List<object>();
foreach (KeyValuePair<string, object> child in children)
{
t.Add("fieldKey", child.Key);
t.Add("value", child.Value);
l.Add(t);
t = new Dictionary<string, object>();
}
separated.Add(src.Key, l.ToArray());
allJson.Add(ser.Serialize(separated));
result.Add(src.Key, l.ToArray());
}
// final string containing all transformed objects combined.
string combined = ser.Serialize(result);
I have two dataTables as follows
1) dtExistingZipCodeInDB (data from database)
2) dtCSVExcelSource (data from csv source which is to be processed)
I have two requirements
1) List all the retired zip codes (zip codes that are present in dtExistingZipCodeInDB but not in dtCSVExcelSource)
2) UnChanged zip codes (zip codes that are present both in dtExistingZipCodeInDB and dtCSVExcelSource)
I can use the Merge to get the retired zip codes. How do I get the unchanged zip codes?
Framework: .Net 3.0
//Note: dtExistingZipCodeInDB and dtCSVExcelSource has the same columns
dtCSVExcelSource.Merge(dtExistingZipCodeInDB);
DataTable dtRetiredZipDataTable = dtCSVExcelSource.GetChanges();
string retiredZipCodes = GetStringFromDataTable(dtRetiredZipDataTable, "ZipCode");
Thanks
Lijo
With the .NET 3.0 requirement, the Intersect LINQ extension method is not available, but you can provide your own extension method.
All you need is the MatchingRows extension method (see below in the demo code) and then do:
IEnumerable<DataRow> unchangedZipCodes = dtExistingZipCodeInDB.MatchingRows(dtCSVExcelSource, "ZipCode");
Then you can loop over unchangedZipCodes, which will contain only those rows with ZipCodes in common between dtExistingZipCodeInDB and dtCSVExcelSource.
Below is demo code I wrote using LINQPad. I love LINQPad -- it's great for proof of concept or scratchpadding/sandboxing some code quickly. But it is not required for the solution to this question.
void Main()
{
string colname = "ZipCode";
var dt = new DataTable();
dt.Columns.Add(colname, typeof(string));
dt.Rows.Add(new [] { "12345" } );
dt.Rows.Add(new [] { "67890" } );
dt.Rows.Add(new [] { "40291" } );
var dt2 = new DataTable();
dt2.Columns.Add(colname, typeof(string));
dt2.Rows.Add(new [] { "12345" } );
dt2.Rows.Add(new [] { "83791" } );
dt2.Rows.Add(new [] { "24520" } );
dt2.Rows.Add(new [] { "48023" } );
dt2.Rows.Add(new [] { "67890" } );
/// With .NET 3.5 LINQ extensions, it can be done inline.
// var results = dt.AsEnumerable()
// .Select(r => r.Field<string>(colname))
// .Intersect(dt2.AsEnumerable()
// .Select(r => r.Field<string>(colname)));
// Console.Write(String.Join(", ", results.ToArray()));
var results = dt.MatchingRows(dt2, colname);
foreach (DataRow r in results)
Console.WriteLine(r[colname]);
}
public static class Extensions
{
/// With .NET 3.0 and no LINQ, create an extension method using yield.
public static IEnumerable<DataRow> MatchingRows(this DataTable dt, DataTable dtCompare, string colName)
{
foreach (DataRow r in dt.Rows)
{
if (dtCompare.Select(String.Format("{0} = {1}", colName, r[(colName)])).Length > 0)
yield return r;
}
}
}
Outputs:
12345
67890