Convert objects to JSON in C# - json

I have a class:
public class StatististikaByCustomer
{
public string data { get; set; } // Array or String?
public string xkey {get;set;}
public Array ykey {get;set;}
public Array labels {get;set;}
}
How can I get JSON like this?
{
"data":[
{
"timeinterval":"2015-10-22T00:00:00",
"Firm":4,
"Firm1":4,
"Firm2":22,
"Firm3":30,
"Firm4":19
},
{
"timeinterval":"2015-10-23T00:00:00",
"Firm":2,
"Firm1":5,
"Firm2":29,
"Firm3":34,
"Firm4":219
}
],
"xkey":"timeinterval",
"ykey":["Firm","Firm1","Firm2","Firm3","Firm4"],
"labels":[" Firm","Firm1","Firm2","Firm3","Firm4"]
}
Firm cannot be hard coded. It all must be dynamic.
My Controller Action:
public JsonResult StatistikaJson()
{
ArrayList arrayList = new ArrayList();
StatistikaByCustomer statisikaObject = new StatistikaByCustomer();
List<Data> listData = new List<Data>();
string jsonTemp = null;
DbDataReader reader = null;
using (var cmd = db.Database.Connection.CreateCommand())
{
if (db.Database.Connection.State == ConnectionState.Closed)
{
db.Database.Connection.Open();
}
cmd.CommandText = "EXEC GetClientConnectsByCustomer #start='" + DateTime.Now.AddMonths(-1).Date.ToString("yyyy-MM-dd") + "',#end='" + DateTime.Now.Date.ToString("yyyy-MM-dd") + "',#interval = 24";
reader = cmd.ExecuteReader();
var tempYkey = Enumerable.Range(1, reader.FieldCount - 1).Select(reader.GetName).ToArray();
statisikaObject.ykey = tempYkey.Select(x => x.Replace(" ", "")).ToArray();
if (reader.HasRows)
{
while (reader.Read())
{
string name = reader.GetName(0);
object value = reader.GetDateTime(0);
listData.Add(new Data() { Name = name, Value = value });
for (int i = 1; i < reader.FieldCount - 1; i++)
{
name = reader.GetName(i).Replace(" ", "");
value = reader.GetInt32(i);
listData.Add(new Data() { Name = name, Value = value });
}
//arrayList.Add(JsonConvert.SerializeObject(listData.ToDictionary(x => x.Name, y => y.Value)));
jsonTemp += JsonConvert.SerializeObject(listData.ToDictionary(x => x.Name, y => y.Value));
jsonTemp += ",";
listData.Clear();
//Debug.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", reader.GetName(0), reader.GetDateTime(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3), reader.GetInt32(4));
}
}
else
{
Debug.WriteLine("No rows found.");
}
statisikaObject.xkey = reader.GetName(0);
statisikaObject.labels = Enumerable.Range(1, reader.FieldCount - 1).Select(reader.GetName).ToArray();
reader.Close();
//the number of affected records, if the query returns it var result = cmd.ExecuteNonQuery();
//or a single scalar value //var result = cmd.ExecuteScalar();
//or even a data reader var result = cmd.ExecuteReader();
db.Database.Connection.Close();
}
statisikaObject.data = oSerializer.Serialize(arrayList);
//string json = JsonConvert.SerializeObject(statisikaObject);
//string json = JsonConvert.SerializeObject(l);
return Json(statisikaObject, JsonRequestBehavior.AllowGet);
}
I get JSON, but it's escaped and morris.js doesn't like it.
In my view, I would like to use it like this:
<script type="text/javascript">
$.getJSON('#Url.Action("StatistikaJson")', function (result)
{
new Morris.Line({
element: 'line-example',
data: result.data,
xkey: "timeinterval",
ykeys: result.ykey,
labels: result.labels
});
});
</script>
I can use Json.NET if necessary. If posible, I would like to get ride off the JSON string appending. I would like to have an array and call serialize to get data: json objects in array format that morris.js needs: http://jsbin.com/uqawig/441/embed?js,output
{"data":"{"timeinterval":"2015-10-22T00:00:00","Firm":4,...},{"timeinterval":"2015-10-22T00:00:00","Firm":5,...},...}

ViewModel:
public class StatistikaByCustomer
{
public ArrayList data { get; set; }
public string xkey { get; set; }
public List<string> ykey { get; set; }
public List<string> labels { get; set; }
}
Controller:
public JsonResult StatistikaJson()
{
StatistikaByCustomer statisikaObject = new StatistikaByCustomer();
ArrayList arrayList = new ArrayList();
List<Data> listData = new List<Data>();
DbDataReader reader = null;
using (var cmd = db.Database.Connection.CreateCommand())
{
if (db.Database.Connection.State == ConnectionState.Closed)
{
db.Database.Connection.Open();
}
cmd.CommandText = "EXEC GetClientConnectsByCustomer #start='" + DateTime.Now.AddMonths(-1).Date.ToString("yyyy-MM-dd") + "',#end='" + DateTime.Now.Date.ToString("yyyy-MM-dd") + "',#interval = 24";
reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
string name = reader.GetName(0);
object value = reader.GetDateTime(0).ToString("yyyy-MM-dd");
listData.Add(new Data() { Name = name, Value = value });
for (int i = 1; i <= reader.FieldCount - 1; i++)
{
name = reader.GetName(i).Replace(" ", "");
value = reader.GetInt32(i);
listData.Add(new Data() { Name = name, Value = value });
}
arrayList.Add(JsonConvert.SerializeObject(listData.ToDictionary(x => x.Name, y => y.Value)));
listData.Clear();
//Debug.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", reader.GetName(0), reader.GetDateTime(0), reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3), reader.GetInt32(4));
}
}
statisikaObject.data = arrayList;
statisikaObject.xkey = reader.GetName(0);
statisikaObject.labels = Enumerable.Range(1, reader.FieldCount - 1).Select(reader.GetName).ToList();
var tempYkey = Enumerable.Range(1, reader.FieldCount - 1).Select(reader.GetName).ToArray();
statisikaObject.ykey = tempYkey.Select(x => x.Replace(" ", "")).ToList();
reader.Close();
db.Database.Connection.Close();
}
return Json(statisikaObject, JsonRequestBehavior.AllowGet);
}
View:
<script type="text/javascript">
$.getJSON('#Url.Action("StatistikaJson")', function (result)
{
new Morris.Line({
element: 'line-example',
data: $.parseJSON("[" + result.data + "]"),
xkey: result.xkey,
ykeys: result.ykey,
labels: result.labels
});
});
</script>

public class Datum
{
public string timeinterval { get; set; }
public int Firm { get; set; }
public int Firm1 { get; set; }
public int Firm2 { get; set; }
public int Firm3 { get; set; }
public int Firm4 { get; set; }
}
public class RootObject
{
public List<Datum> data { get; set; }
public string xkey { get; set; }
public List<string> ykey { get; set; }
public List<string> labels { get; set; }
}
By putting this code get Serialize json string
var collection = new List<RootObject>();
dynamic collectionWrapper = new
{
people = new RootObject()
{
xkey = "timeinterval",
data = new List<Datum>
{
new Datum()
{
timeinterval = "2015-10-22T00: 00: 00",
Firm = 4,
Firm1= 4,
Firm2= 22,
Firm3= 30,
Firm4= 19
},
new Datum()
{
timeinterval = "2015-10-23T00: 00: 00",
Firm = 2,
Firm1= 5,
Firm2= 29,
Firm3= 34,
Firm4= 219
}
},
ykey = new List<string> { "Firm", "Firm1", "Firm2", "Firm3", "Firm4" },
labels = new List<string> { "Firm", "Firm1", "Firm2", "Firm3", "Firm4" }
}
};
var output = JsonConvert.SerializeObject(collectionWrapper);
Edit:
var collection = new StatististikaByCustomer
{
xkey = "timeinterval",
ykey = new List<string>{"Firm","Firm1","Firm2","Firm3","Firm4"},
labels = new List<string> { "Firm", "Firm1", "Firm2", "Firm3", "Firm4" },
data = new Dictionary<string, string>
{
{ "timeinterval", "2015-10-22T00: 00: 00" },
{ "Firm", "4" },
{ "Firm1", "4" },
{ "Firm2", "22" },
{ "Firm3", "30" },
{ "Firm4", "19" }
}
};
string json = JsonConvert.SerializeObject(collection);
Class:
public class StatististikaByCustomer
{
public string xkey { get; set; }
public Dictionary<string, string> data { get; set; }
public List<string> ykey { get; set; }
public List<string> labels { get; set; }
}
Update:
var collection = new StatististikaByCustomer
{
xkey = "timeinterval",
ykey = new List<string> { "Firm", "Firm1", "Firm2", "Firm3", "Firm4" },
labels = new List<string> { "Firm", "Firm1", "Firm2", "Firm3", "Firm4" },
data = new List<Dictionary<string,string>>
{
new Dictionary<string, string>
{
{ "timeinterval", "2015-10-22T00: 00: 00" },
{ "Firm", "4" },
{ "Firm1", "4" },
{ "Firm2", "22" },
{ "Firm3", "30" },
{ "Firm4", "19" }
},
new Dictionary<string, string>
{
{ "timeinterval", "2015-10-23T00: 00: 00" },
{ "Firm", "2" },
{ "Firm1", "5" },
{ "Firm2", "29" },
{ "Firm3", "34" },
{ "Firm4", "219" }
}
}
};
string json = JsonConvert.SerializeObject(collection);
Class:
public class StatististikaByCustomer
{
public string xkey { get; set; }
public List<Dictionary<string, string>> data { get; set; }
public List<string> ykey { get; set; }
public List<string> labels { get; set; }
}

Related

ChartJS shows chart but no data in ASP net core

Im trying to display some data comming from API request into a Chart JS bar chart.
Model:
public class MachineApiModel
{
public string id { get; set; }
public Production[] productions { get; set; }
public string customerId { get; set; }
public string siteId { get; set; }
public string brand { get; set; }
public string type { get; set; }
public string serialNumber { get; set; }
public string line { get; set; }
public string ipAdres { get; set; }
public int port { get; set; }
public DateTime created { get; set; }
public DateTime changed { get; set; }
}
public class Production
{
public string id { get; set; }
public string machineId { get; set; }
public string purchaseOrder { get; set; }
public DateTime startTime { get; set; }
}
public class ProductionChartModel
{
[JsonProperty(PropertyName = "Brand")]
public List<string> Brand { get; set; }
[JsonProperty(PropertyName = "Port")]
public List<int> Port { get; set; }
}
Controller: (Recieving list of machine model comming from API call):
public async Task<List<MachineApiModel>> GetMachineApiAsync()
{
List<MachineApiModel> Machines = new List<MachineApiModel>();
HttpClient client = _api.Init();
HttpResponseMessage res = await client.GetAsync("Machine");
if (res.IsSuccessStatusCode)
{
try
{
var result = await res.Content.ReadAsStringAsync();
Machines = JsonConvert.DeserializeObject<List<MachineApiModel>>(result);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Something went wrong");
}
}
return Machines;
}
Index.cshtml.cs:
I can see that the JsonResult is filled from the model data. So this is working.
private readonly MachineController _machineController = new();
private readonly ILogger<IndexModel> _logger;
[BindProperty]
public List<MachineApiModel> MachineApiModel { get; set; }
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public async Task<IActionResult> OnGet()
{
MachineApiModel = await _machineController.GetMachineApiAsync();
return Page();
}
public async Task<JsonResult> OnGetChartData()
{
MachineApiModel = await _machineController.GetMachineApiAsync();
var chartModel = new ProductionChartModel();
chartModel.Brand = new List<string>();
chartModel.Port = new List<int>();
foreach (var inv in MachineApiModel)
{
chartModel.Brand.Add(inv.brand);
chartModel.Port.Add(inv.port);
}
return new JsonResult(chartModel);
}
Index.cshtml:
The chart is drawn on the page but the data is not displayed for some reason. This is where i get stuck. So its basically a empty chart.
<p>Charts</p>
<div class="container">
<canvas id="chart" width="500" height="300"></canvas>
</div>
<script>
var myAmounts = [];
var myCategories = [];
var Machines;
function showChart() {
myAmounts = Machines.Port;
myCategories = Machines.Brand;
console.log(myAmounts);
console.log(myCategories);
let popCanvasName = document.getElementById("chart");
let barChartName = new Chart(popCanvasName, {
type: 'bar',
data: {
labels: myCategories,
datasets: [{
label: 'Machines',
data: myAmounts,
backgroundColor: [
'rgba(255, 99, 132, 0.6)',
'rgba(54, 162, 235, 0.6)',
'rgba(255, 206, 86, 0.6)',
'rgba(75, 192, 192, 0.6)',
'rgba(153, 102, 255, 0.6)',
]
}]
},
options: {
responsive: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
}
function getChartData() {
return fetch('./Index?handler=ChartData',
{
method: 'get',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
.then(function (response) {
if (response.ok) {
return response.text();
} else {
throw Error('Response Not OK');
}
})
.then(function (text) {
try {
return JSON.parse(text);
} catch (err) {
throw Error('Method Not Found');
}
})
.then(function (responseJSON) {
Machines = responseJSON;
showChart();
})
}
getChartData();
</script>
You could add console.log(Machines) to check the response in Console panel. Then you will find the property name in response is camel case.
Change your code below:
function showChart() {
myAmounts = Machines.port;
myCategories = Machines.brand;
//.....
}

How to mock PATCH methods of WebAPI using MS Unit?

I have the following PATCH method for which I am writing Unit Tests.
[HttpPatch("{id}")]
public IActionResult Patch(Guid id, [FromBody] JsonPatchDocument<QuoteDraft> patch) {
Global.AccessToken = Request.Headers["Authorization"];
var draft = new QuoteDraft();
var json = string.Empty;
try {
draft = quoteDraftRepository.GetQuoteDraftById(id);
if (draft == null) {
throw new ArgumentException($"Draft quote not found for id {id}");
}
QuoteDraft quoteDraft = null;
foreach (var item in patch.Operations) {
json = Convert.ToString(item.value);
var lineItem = JsonConvert.DeserializeObject<LineItem>(json);
quoteDraft = AddLineItem(draft, lineItem);
}
return StatusCode(StatusCodes.Status200OK, new QuoteDraftResponse {
Message = messageHandler.GetMessage(MessageType.All),
QuoteDraft = quoteDraft
});
}
Below is my unit test method:
[testmethod]
public void patchtestmethod()
{
var jsonobject = new jsonpatchdocument<quotedraft>();
var quotedraft = new quotedraft
{
market = "noo",
program = "ils",
brochure = "2019",
season = "v1",
currency = "nok",
totalprice = 100,
};
var value = jsonconvert.serializeobject(quotedraft);
jsonobject.add("/lineitem/-", value);
quotecontroller.patch(it.isany<guid>(), jsonobject);
}
I am getting the error as shown in below screenshot:
Error Details
The json patch has to look something like this.
op: 'add',
path: '/lineItem/-',
value: {
destination: this.props.result.destination.code,
currency: this.props.result.currency.code,
sku: getSku(this.props.result.course.code, this.props.result.destination.code),
unitType: this.props.result.course.unitType,
startDate: format(this.props.result.startDate),
endDate: this.props.result.endDate,
quantity: this.props.result.numberOfWeeks.id,
category: 'Course',
language: 'NO',
departurePoint: this.props.result.departure ? this.props.result.departure.code : null,
description: this.props.result.course.description
},
Kindly let me know what I am missing.
Thanks
For jsonobject.Add, it accpets Expression<Func<TModel, TProp>> path which is used to define the path for this operation.
Model.cs
public class QuoteDraft
{
public string Market { get; set; }
public string Program
{
get; set;
}
public List<LineItem> LineItem { get; set; }
}
public class LineItem
{
public string Destination { get; set; }
public string Sku { get; set; }
}
Code
var jsonobject = new JsonPatchDocument<QuoteDraft>();
var quotedraft = new QuoteDraft
{
Market = "noo",
Program = "ils"
};
var lineItem = new LineItem
{
Destination = "D",
Sku = "S"
};
jsonobject.Add(q => q, quotedraft);
jsonobject.Add(q => q.LineItem, lineItem);
var value = JsonConvert.SerializeObject(jsonobject);

Json serialization in MVC

Below are my two model classes
public class ResponseData
{
public List<string> labels { get; set; }
public List<string> series { get; set; }
public List<dataForMetric> data{ get; set; }
}
public class dataForMetric
{
public List<int> value { get; set; }
}
and my action method is
public ActionResult GetData()
{
ResponseData res = new ResponseData();
res.labels = new List<string>() { "day1", "day2", "day3" , "day4"};
res.series = new List<string>() { "dummy" };
res.data = new List<dataForMetric>() { new dataForMetric() { value = new List<int>() {10} } ,
new dataForMetric() { value = new List<int>() {110} } ,
new dataForMetric() { value = new List<int>() {120} } ,
new dataForMetric() { value = new List<int>() {130} }
};
return Json(res, JsonRequestBehavior.AllowGet);
}
The JSON output of above action method is
{"labels":["day1","day2","day3","day4"],"series":["dummy"],"data":[{"value":[10]},{"value":[110]},{"value":[120]},{"value":[130]}]}
But for my requirement the output should be
{"labels":["day1","day2","day3","day4"],"series":["dummy"],"data":[[10],[110],[120],[130]]}
Please let me know how it can be achieved.
Well if you actually want output like you describe you should chenge your class to this:
public class ResponseData
{
public List<string> labels { get; set; }
public List<string> series { get; set; }
public int[][] data { get; set; }
}
I generate this class with VS 2013. It now has feature to create class structure from JSON. Edit -> Paste Special -> Pase JSON as classes. Hope this instrument will ease your life a lot.
Your dataForMetric class is unnecessary. You can achieve the desired result with a list of lists:
public class ResponseData
{
public List<string> labels { get; set; }
public List<string> series { get; set; }
public List<List<int>> data { get; set; }
}
public ActionResult GetData()
{
ResponseData res = new ResponseData();
res.labels = new List<string> { "day1", "day2", "day3" , "day4"};
res.series = new List<string> { "dummy" };
res.data = new List<List<int>> {
new List<int> { 10 },
new List<int> { 110 },
new List<int> { 120 },
new List<int> { 130 }
};
return Json(res, JsonRequestBehavior.AllowGet);
}
You must either define data as a single dataForMetric or define dataForMetric.value as a single int.
Your problem is you're instantiating a List of a List of int.

How to use Postback in ASP.net MVC

How to preserve the selected value after postback for that dropdownlist?
I have used two dropdown lists in my application. I need to search the gridview data based on the selected values of dropdownlist. The searched data is displayed in the pagedlist format. But when i move to next page of pagedlist, its displaying the whole grid view data rather than searched data. so any help will be appreciated.
My Model
namespace CCIOfficeServiceManagementSystem.Models
{
public class AirtelManagementModel
{
public long MobileAcNumber { get; set; }
public long AirtelNumber { get; set; }
public int OneTime { get; set; }
public float MonthlyCharges { get; set; }
public float CallCharges { get; set; }
public float ValueAddedServices { get; set; }
public float MobileInternetUsage { get; set; }
public float Roaming{ get; set; }
public float Discounts { get; set; }
public float Taxes { get; set; }
public float TotalCharges { get; set; }
public string WhoUploaded { get; set; }
public DateTime UploadedDate { get; set; }
public DateTime DateOfCreation { get; set; }
public int ImportDateId { get; set; }
public List<MonthListClass> MonthList
{
get;
set;
}
public List<clsYearOfDate> YearList
{
get;
set;
}
}
public class MonthListClass
{
public int MonthSelectedId { get; set; }
public string MonthName { get; set; }
}
public class clsYearOfDate
{
public int YearSelectedId { get; set; }
public string YearOfDate { get; set; }
}
}
My View
#using (Html.BeginForm("ViewDataOfDatabase", "AirtelManagement",FormMethod.Post))
{
<h3>Search by PhoneNumber:#Html.TextBox("SearchString",ViewBag.CurrentFilter as string)</h3>
<p><h3>Year:#Html.DropDownList("Yearitems", (IEnumerable<SelectListItem>)ViewBag.SelectList, "Select Year")</h3>
<h3>Month:#Html.DropDownList("MonthItems", (IEnumerable<SelectListItem>)ViewBag.SelectMonthList, "Select Month")</h3>
<h3>City: #Html.DropDownList("CityNames", (IEnumerable<SelectListItem>)ViewBag.CityList, "Select City")</h3></p>
<p><input type="submit" value="Search" /></p>
<script>
$(document).ready(function () {
$("#Yearitems").change(function () {
//debugger;
//alert($("#Yearitems>option:selected").attr("Value"));
$.ajax({
type: "Post",
url: '#Url.Action("GetMonths","AirtelManagement")',
data: { YearId: $("#Yearitems>option:selected").attr("Value") },
datatype: "Json",
success: function (data) {
//debugger;
$("#MonthItems").html("");
$.each(data, function (index, item) {
$("#MonthItems").append(new Option(item.MonthName, item.MonthSelectedId));
});
},
error: function () {
alert("Select Year");
}
});
});
});
</script>
My controller's action Method
public ActionResult ViewDataOfDatabase(string sortorder, string currentFilter, string searchString, int? page,FormCollection collection)
{
CCIRepository _repository = CCIRepository.CreateRepository();
AirtelManagementModel _Airtelmodel = new AirtelManagementModel();
IEnumerable<CityListClass> CityList = _repository.GetCities();
IEnumerable<SelectListItem> CityListItems = from c in CityList
select new SelectListItem()
{
Value = c.CityName.ToString(),
Text = c.CityName.ToString(),
Selected = c.CityName == Request["CityNames"],
};
ViewBag.CityList = CityListItems;
IEnumerable<clsYearOfDate> SelectList = GetYears();
//IEnumerable<MonthListClass> SelectMonthList = GetMonths(YearId);
IEnumerable<SelectListItem> Yearitems = (from v in SelectList
select new SelectListItem()
{
Value = v.YearSelectedId.ToString(),
Text = v.YearOfDate.ToString(),
Selected = v.YearOfDate == Request["Yearitems"],
});
ViewBag.SelectList = Yearitems;
int DateId=0;
string CityName = string.Empty;
try
{
int SelectedYear = Convert.ToInt16(collection["Yearitems"].ToString());
int SelectedMonth = Convert.ToInt16(collection["MonthItems"].ToString());
CityName = collection["CityNames"].ToString();
DateId = _repository.GetImportDateId(SelectedYear, SelectedMonth);
}
catch(NullReferenceException Ex)
{
}
//IEnumerable<SelectListItem> MonthItems = (from m in SelectMonthList
// select new SelectListItem()
// {
// Value = m.MonthSelectedId.ToString(),
// Text = m.MonthName,
// });
//ViewBag.SelectMonthList = MonthItems;
IEnumerable<SelectListItem> MonthItems = Enumerable.Empty<SelectListItem>();
ViewBag.SelectMonthList = MonthItems;
List<AirtelManagementModel> list = ViewDetails();
ViewBag.CurrentSort = sortorder;
ViewBag.PhoneSortParm = String.IsNullOrEmpty(sortorder) ? "Phone_desc" : "";
if (searchString != null )
{
page = 1;
}
else
{
searchString = currentFilter;
}
//if(searchString!=null)
//{
ViewBag.CurrentFilter = searchString;
var airteldetails = from _model in list
select _model;
if(!String.IsNullOrEmpty(searchString) && DateId!=0 && !String.IsNullOrEmpty(CityName))
{
airteldetails = _repository.FilterAirtelDetails(searchString, DateId, CityName);
int PageSize = 5;
int PageNumber = (page ?? 1);
return View(airteldetails.ToPagedList(PageNumber, PageSize));
}
//airteldetails=airteldetails.OrderByDescending(A=>A.AirtelNumber);
int pageSize = 5;
int pageNumber = (page ?? 1);
//return View(airteldetails.ToList());
return View(airteldetails.ToPagedList(pageNumber, pageSize));
//}
//if (list.Count > 0)
//{
// var airteldetails = from _model in list
// select _model;
// return View(airteldetails.ToPagedList(pageNumber,pageSize));
//}
//else
//{
// ModelState.AddModelError("Error", "No Data found in Database");
// return RedirectToAction("ImportExcelFile", "AirtelManagement");
//}
}

Windows Phone, How to deserialize json which has nested Array

I am now doing a windows phone project, and need to request to a web service for some json data.
if the json structure is like
[Dictionary1,
Dictionary2,
Dictionary3
]
then, DataContractJsonSerializer works fine.
but the next request i will get a complex json data, it doesn't work. like
[
[Dictionary1],
[Dictionary2],
[Dictionary3]
]
real data is:
[
[{"length":5734.042,"duration":1680,"legs":
[
{"length":685,"duration":555.42,"type":"walk","locs":
[
{"coord":{"x":2546445,"y":6675512},"arrTime":"201203290959","depTime":"201203290959","name":null},
{"coord":{"x":2546433.8,"y":6675498.3},"arrTime":"201203291000","depTime":"201203291000","name":"Teekkaripolku"}
]
},
{"length":4158,"duration":420,"type":"5","code":"2506 2","locs":
[
{"coord":{"x":2546168,"y":6674959},"arrTime":"201203291009","depTime":"201203291009","name":"Alvar Aallon puisto","code":"2222235","shortCode":"E2226","stopAddress":"Otaniementie"},
{"coord":{"x":2546337,"y":6674857},"arrTime":"201203291009","depTime":"201203291009","name":"Dipoli","code":"2222204","shortCode":"E2204","stopAddress":"Otaniementie"}
]
}
]
}],
[{"length":5734.042,"duration":1680,"legs":
[
{"length":685,"duration":555.42,"type":"1", "code":"1111", "locs":
[
{"coord":{"x":2546445,"y":6675512},"arrTime":"201203290952","depTime":"201203290952","name":null},
{"coord":{"x":2546433.8,"y":6675498.3},"arrTime":"201203290953","depTime":"201203290953","name":"Teekkaripolku"}
]
},
{"length":4158,"duration":420,"type":"5","code":"2194 2","locs":
[ {"coord":{"x":2546168,"y":6674959},"arrTime":"201203291002","depTime":"201203291002","name":"Alvar Aallon puisto","code":"2222235","shortCode":"E2226","stopAddress":"Otaniementie"},
{"coord":{"x":2546337,"y":6674857},"arrTime":"201203291002","depTime":"201203291002","name":"Dipoli","code":"2222204","shortCode":"E2204","stopAddress":"Otaniementie"}
]
}
]
}]
]
and the class models are :
[DataContract]
public class RouteList
{
[DataMember]
public List<Route> oneRoute;
}
---
[DataContract]
public class Route
{
[DataMember(Name = "length", IsRequired = true)]
public Double length { get; set; }
[DataMember(Name = "duration", IsRequired = true)]
public Double duration { get; set; }
[DataMember(Name = "legs", IsRequired = true)]
public List<Leg> legs { get; set; }
}
----
[DataContract]
public class Leg
{
[DataMember(Name = "length", IsRequired = true)]
public Double length { get; set; }
[DataMember(Name = "duration", IsRequired = true)]
public Double duration { get; set; }
[DataMember(Name = "type", IsRequired = true)]
public String type { get; set; }
[DataMember(Name = "code", IsRequired = false)]
public String code { get; set; }
[DataMember(Name = "locs", IsRequired = true)]
public List<Loc> locs { get; set; }
[DataMember(Name = "shape", IsRequired = false)]
public String shape { get; set; }
}
-----
[DataContract]
public class Loc
{
[DataMember(Name = "coord", IsRequired = true)]
public String coord { get; set; }
[DataMember(Name = "arrTime", IsRequired = true)]
public String arrTime { get; set; }
[DataMember(Name = "depTime", IsRequired = true)]
public String depTime { get; set; }
[DataMember(Name = "name", IsRequired = true)]
public String name { get; set; }
[DataMember(Name = "code", IsRequired = false)]
public String code { get; set; }
[DataMember(Name = "shortCode", IsRequired = false)]
public String shortCode { get; set; }
[DataMember(Name = "stopAddress", IsRequired = false)]
public String stopAddress { get; set; }
}
and the deserializing code:
System.IO.MemoryStream mStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(e.Result));
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<RouteList>));
result = (List<RouteList>)serializer.ReadObject(mStream);
i have tried DataContractJsonSerializer and json.NET. but failed. and the most possible problem is the nested arrays, the model:RouteList. anyone knows how to fix it? Thanks a lot.
The issue may be because of your class creation, Before concluding check you model class that handle you parsed result. Or if you want help add more information, like the structure of your model class, the code you used for parsing json etc. Here it seems nothing is complected. Json.Net will do all the tricks, the only effort you need to take is proper building of you class type ..
Enjoy Coding
with the help of Olli Saarikivi, the problem is solved.
with his permission, post his solution here, in case anybody else may need it.
// The request response handler
var routeResults = new List<CompoundRoute>();
if (e.Result.Trim().Length != 0)
{
JArray json = JArray.Parse(e.Result);
foreach (var token in json)
{
var routeArray = token as JArray;
if (routeArray != null)
{
var compoundRoute = new CompoundRoute { Routes = new Route[routeArray.Count] };
for (int i = 0; i < compoundRoute.Routes.Length; ++i)
{
compoundRoute.Routes[i] = new Route(routeArray[i]);
}
routeResults.Add(compoundRoute);
}
}
}
// The data model
[DataContract]
public class CompoundRoute
{
private static readonly Route[] EmptyRoutes = new Route[0];
public CompoundRoute()
{
Routes = EmptyRoutes;
}
[DataMember]
public Route[] Routes;
}
[DataContract]
public class Route
{
public Route(JToken token)
{
Length = token.Value<double>("length");
int durationSeconds = token.Value<int>("duration");
Duration = TimeSpan.FromSeconds(durationSeconds);
JArray legTokens = token["legs"] as JArray;
if (legTokens != null)
{
Legs = new Leg[legTokens.Count];
for (int i = 0; i < Legs.Length; ++i)
{
Legs[i] = new Leg(legTokens[i]);
}
}
}
[DataMember]
public double Length;
[DataMember]
public TimeSpan Duration;
[DataMember]
public Leg[] Legs;
}
[DataContract]
public class Leg
{
public Leg(JToken token)
{
Length = token.Value<double>("length");
double durationSeconds = token.Value<double>("duration");
Duration = TimeSpan.FromSeconds((int)Math.Round(durationSeconds));
Type = token.Value<string>("type");
string lineCode = token.Value<string>("code");
if (lineCode != null)
{
Line = App.Cache.GetOrCreate(lineCode, () => new Line(lineCode));
}
if (Type == "12") // Commuter trains
{
Line.ShortName = Utils.RemoveLeadingNumbers(Line.ShortName);
}
JArray locTokens = token["locs"] as JArray;
if (locTokens != null)
{
Locs = new LegLocation[locTokens.Count];
for (int i = 0; i < Locs.Length; ++i)
{
Locs[i] = new LegLocation(locTokens[i]);
}
}
else
{
Locs = new LegLocation[0];
}
JArray shapeTokens = token["shape"] as JArray;
if (shapeTokens != null)
{
Shape = new ReittiCoordinate[shapeTokens.Count];
for (int i = 0; i < Shape.Length; ++i)
{
var shapeToken = shapeTokens[i];
double x = shapeToken.Value<double>("x");
double y = shapeToken.Value<double>("y");
var coordinate = new ReittiCoordinate(y, x);
Shape[i] = coordinate;
}
}
}
[DataMember]
public double Length;
[DataMember]
public TimeSpan Duration;
[DataMember]
public string Type;
[DataMember]
public Line Line;
[DataMember]
public LegLocation[] Locs;
[DataMember]
public ReittiCoordinate[] Shape;
}
[DataContract]
public class LegLocation
{
public LegLocation(JToken token)
{
var coordToken = token["coord"];
double x = coordToken.Value<double>("x");
double y = coordToken.Value<double>("y");
Coord = new ReittiCoordinate(y, x);
string arrTimeString = token.Value<string>("arrTime");
ArrTime = DateTime.ParseExact(arrTimeString, "yyyyMMddHHmm", null);
string depTimeString = token.Value<string>("depTime");
DepTime = DateTime.ParseExact(depTimeString, "yyyyMMddHHmm", null);
Name = token.Value<string>("name");
}
[DataMember]
public ReittiCoordinate Coord;
[DataMember]
public DateTime ArrTime;
[DataMember]
public DateTime DepTime;
[DataMember]
public string Name;
}