0

I'm trying to populate a Highcharts chart via a javascript call from ASP.Net, I'm using JSON.Net to serialize data for the chart. However, I can't get the JSON created from my datasource to match the formatting that seems to be required by Highcharts. To see the problem you need only examine the X axis (categories), for example...

[{\"category\":\"August 15 and 16, 2014\"},{\"category\":\"March 21st, 2014\"},{\"category\":\"January 17 and 18, 2014\"},{\"category\":\"August 16 and 17, 2013\"},{\"category\":\"March 22nd, 2013\"},{\"category\":\"January 18 and 19, 2013\"},{\"category\":\"August 17 and 18, 2012\"},{\"category\":\"March 16th, 2012\"},{\"category\":\"January 20 and 21, 2012\"},{\"category\":\"August 19 and 20, 2011\"},{\"category\":\"January 21 and 22, 2011\"}]

should be like this...

['August 15 and 16, 2014', 'March 21st, 2014', 'January 17 and 18, 2014', 'August 16 and 17, 2013', 'March 22nd, 2013', 'January 18 and 19, 2013', 'August 17 and 18, 2012', 'March 16th, 2012', 'January 20 and 21, 2012', 'August 19 and 20, 2011', 'January 21 and 22, 2011']

So essentially my serialization is creating a list of objects, where all I need is an array of values. To fix this I either need to generate an array of values, or get the Highcharts constructor to read the objects.

ASP.Net codebehind...

var tblNormal = Reporting.GetHistoricalTicketSalesReport();

    var queryX = from row in tblNormal.AsEnumerable()
        select new
        {
            category = row.ShowDateDescription
        };
    JObject o = JObject.FromObject(new
    {
        categories = queryX
    });
    string strXJSON = o.ToString();
    // value is: "{\"categories\":[{\"category\":\"August 15 and 16, 2014\"},{\"category\":\"March 21 and 21, 2014\"},{\"category\":\"January 17 and 18, 2014\"},{\"category\":\"August 16 and 17, 2013\"},{\"category\":\"March 22 and 22, 2013\"},{\"category\":\"January 18 and 19, 2013\"},{\"category\":\"August 17 and 18, 2012\"},{\"category\":\"March 16 and 16, 2012\"},{\"category\":\"January 20 and 21, 2012\"},{\"category\":\"August 19 and 20, 2011\"},{\"category\":\"January 21 and 22, 2011\"}]}"

    var queryY = from row in tblNormal.AsEnumerable()
        select new HighChartsPoint
        {
            y = row.TicketsSold
        };
    o = JObject.FromObject(new
    {
        series = queryY
    });
    string strYJSON = o.ToString();

    //This removes the wrapper around the inner JSON data
    strXJSON = F.AllAfter(strXJSON, ":").TrimEnd('}');
    //value is: "[{\"category\":\"August 15 and 16, 2014\"},{\"category\":\"March 21 and 21, 2014\"},{\"category\":\"January 17 and 18, 2014\"},{\"category\":\"August 16 and 17, 2013\"},{\"category\":\"March 22 and 22, 2013\"},{\"category\":\"January 18 and 19, 2013\"},{\"category\":\"August 17 and 18, 2012\"},{\"category\":\"March 16 and 16, 2012\"},{\"category\":\"January 20 and 21, 2012\"},{\"category\":\"August 19 and 20, 2011\"},{\"category\":\"January 21 and 22, 2011\"}]"
    strYJSON = F.AllAfter(strYJSON, ":").TrimEnd('}');

    //Call the function on the client browser
    ExecuteJavascript("InitShowChart(" + strXJSON + ", " + strYJSON + ");");
3
  • It sounds like you are not supposed to use JSON as the input. Why don't you just override the ToString() to return what you want, or write a method that will do it for you ? Commented Aug 13, 2014 at 5:57
  • Because I'm attempting to solve the problem without writing my own library for Serialization, not because I'm lazy (it would save me time), but because JSON spec may change in the future and I'd prefer that all my JSON be generated by a library that will keep up with the times automatically. Commented Aug 13, 2014 at 6:02
  • As I see your json has incorrect form, because doesnt contain any y paramer which is value. Commented Aug 14, 2014 at 8:43

4 Answers 4

3

From your json, it seems that the class definitions you need to declare should be something like this (see http://json2csharp.com/):

public class Title
{
    public string text { get; set; }
    public int x { get; set; }
}

public class Subtitle
{
    public string text { get; set; }
    public int x { get; set; }
}

public class XAxis
{
    public List<string> categories { get; set; }
}

public class PlotLine
{
    public int value { get; set; }
    public int width { get; set; }
    public string color { get; set; }
}

public class YAxis
{
    public Title title { get; set; }
    public List<PlotLine> plotLines { get; set; }
}

public class Tooltip
{
    public string valueSuffix { get; set; }
}

public class Legend
{
    public string layout { get; set; }
    public string align { get; set; }
    public string verticalAlign { get; set; }
    public int borderWidth { get; set; }
}

public class Series
{
    public string name { get; set; }
    public List<double?> data { get; set; }
}

public class HighChartsData
{
    public Title title { get; set; }
    public Subtitle subtitle { get; set; }
    public XAxis xAxis { get; set; }
    public YAxis yAxis { get; set; }
    public Tooltip tooltip { get; set; }
    public Legend legend { get; set; }
    public List<Series> series { get; set; }
}

if you declare a variable

var data = new HighChartsData();

fill its properties and serialize as

var json = JsonConvert.SerializeObject(data);

your json will be ready. No need to create the json manually.

Sign up to request clarification or add additional context in comments.

3 Comments

wouldn't this simply create a json for the class with inner structs? (assuming inner classes inside HighChartsData are the above), and which still won't be the output he expects?
@Noctis I don't get you. How about updating your answer with what you think is correct?
From what I've understood, he wanted to use just the values, without the "headers" or property names. Json obviously pairs property value name to actual value, as strings. So if you want the input to look like what he asked for, it wouldn't be a JSON really. But, since he solved it, it doesn't matter anymore :)
1

First, you can use NewtonSoft JSON. He's quite updated, and mantains his library often.

Second, here's an example. Let's assume an example class:

public class AnExample{
    public int AnInt{get;set;}
    public string AString {get;set;}
    public DateTime ADate { get; set; }

    public override string ToString() {
        return "['" + AnInt + "','" + AString +"','"+ADate.ToString("s")+"']";
    }
}

You can write something like:

void Main()
{
    var example = new AnExample() {
          AnInt = 1
        , AString = "Hello"
        , ADate = DateTime.Now
    };

    var examlpe_as_json = Newtonsoft.Json.JsonConvert.SerializeObject(example);
    // -> {"AnInt":1,"AString":"Hello","ADate":"2014-08-13T16:21:56.8348626+10:00"} 

    var input_to_highchart = example.ToString();
    // -> ['1','Hello','2014-08-13T16:21:56']       
}

Json is useful when you need to Deserialize the string later back into a class ...but what you want seems to be an input for your charts. I don't see a way around writing something like the above ToString() or a helper method.

If you don't care about the oreder (I think you do though), you can also leverage some reflection to do this for you, but this is where it starts to get a bit more ... ugly ... :)

Comments

1

I can't tell from your code exactly, but you are probably trying to serialize a List<Category> or IEnumerable<Category> or something similar. This is why you get the [{"category": "xxxxxx"}] construct.

Solution: Instead, first convert this to a string array: string[], then serialize that array. This should result in an array of strings, without objects.

Comments

0

The other answers here are full of good ideas, and some are even better ways to go about this... but here is the essential fix for my presented question.

I changed this...

   var queryX = from row in tblNormal.AsEnumerable()
    select new
    {
        category = row.ShowDateDescription
    };

To this...

var queryX = from row in tblNormal.AsEnumerable()
                 select row.ShowDateDescription;

That fixed the primary issue, apparently in my lack of LINQ experience I was explicitly declaring a collection of objects. The new version serializes as a list of values only.

With the same approach, I also changed this....

o = JObject.FromObject(new
{
    series = queryY
});
string strYJSON = o.ToString();
strYJSON = F.AllAfter(strYJSON, ":").TrimEnd('}');

to this....

string strYJSON = JArray.FromObject(queryY).ToString(Newtonsoft.Json.Formatting.None);

That change removed the need to use string manipulation after serialization because I am explicitly serializing an Array instead of an Object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.