Creating Charts with ASP.NET Core

The days are gone of server-side generated charts. Today, I show you how to take a JavaScript charting library and use it in ASP.NET Core.

Written by Jonathan "JD" Danylko • Last Updated: • Develop •

Screenshot of a chart on a paper with a laptop

With one of my latest projects, one of the most important pieces I'm working on is charting with ASP.NET Core.

I know I mentioned charts with ASP.NET MVC in the past, but that was close to 5 years ago and we have a whole new cross-platform world with ASP.NET Core 3.1 along with a .NET 5 arriving soon.

I felt this was definitely a good time to revisit charting and examine the options available for ASP.NET Core.

In this post, we'll select a JavaScript library and create a ViewComponent to make life a little easier when using charts in ASP.NET Core.

The New World: Everything JavaScript

When ASP.NET MVC came around, there was already a charting library for the server from Microsoft. The Chart Class in the WebPages 3.2 WebHelper assembly helped to generate charts on the server and then return the image to the client.

That was 5 years ago.

The new normal of creating charts is through the use of this new thing called JavaScript (anyone heard of it? </sarcasm>).

As you know, there are a number of JavaScript charting libraries available through even the biggest companies like Google. The one downside to every JavaScript is the data has to be JSON. It would be easier to retrieve the data and create the chart on the server, then return the generated chart to the client.

However, everyone wants their charts to be dynamic. It's kind of hard to add a new series of data to an axis, change a label, or click on an item to examine data further when you are sent a static image from the server. Interaction and JavaScript go hand-in-hand when it comes to client-side charting.

JavaScript Charting Libraries

Let's select a JavaScript library. Even though there are a ton out there, I've found a couple of mature libraries.

The charting libraries I'm aware of are the following:

I wanted to create a simple demonstration so we'll use ChartsJs for this example.

But how do we send data from C# over to JavaScript to display in our chart.

The Basics of ASP.NET Core ViewComponents

I've worked with TagHelpers for a while and built a couple when Core 1.0 was released. This included Smart Links, Scheduled Links, A/B Tests, and Image Layouts just to name a few.

While they are a little bit out of date, I'm switching gears and working with ViewComponents.

Let's review the basics of ViewComponents.

  • ViewComponents have a specific signature for their tagname. Ours will be chartjs and have a prefix of vc. (i.e. <vc:chartjs>)
  • _ViewImports.cshtml must have an @addTagHelper with the assembly name containing your ViewComponents.
  • ViewComponents can disguise themselves as TagHelper as tags (which looks more natural)
  • ViewComponents are identified by deriving from a ViewComponent, decorating a class with a [ViewComponent] attribute, or creating a class that ends with ViewComponent
  • ViewComponents can be placed anywhere in the project.
  • The Views are placed in the Views/Shared/Components/{viewcomponentname}/default.cshtml directory. You can also customize the search path for your View locations as well. 

Quite a checklist to make sure we are creating a ViewComponent properly, but the dividends are worth it in the end.

Building the Chart Structure

For this example, we'll create the simple chart from the ChartJs page.

However, we need a Json structure for our chart data. The quickest way to create a C# structure from JSON is the following:

  1. Copy the JSON structure in the example (JUST the JSON structure)
  2. Create a new class in Visual Studio 2019
  3. Under Edit -> Paste Special -> Paste Json as classes.
  4. Rename the "RootObject" to "ChartJs"

Voila! You now have a complete C# class that mimics the JSON example required for the chart.

We create the C# class for two reasons:

  1. It's easier to manage a C# class hierarchy instead of concatenating strings.
  2. It can be data-driven by saving titles, labels, and chart types for customization purposes.

Let's move on to the ViewComponent.

Creating the Chart ViewComponent

Now that we have the chart model, we can proceed with our ViewComponent.

Of course, this was a VERY quick implementation of our ViewComponent.

ViewComponents/ChartJsViewComponent.cs

using ChartExample.Models;
using ChartExample.Models.Chart;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace ChartExample.ViewComponents
{
    [ViewComponent(Name = "chartjs")]
    public class ChartJsViewComponent : ViewComponent
    {
        public IViewComponentResult Invoke()
        {
            // Ref: https://www.chartjs.org/docs/latest/
            var chartData = @"
            {
                type: 'bar',
                responsive: true,
                data:
                {
                    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
                    datasets: [{
                        label: '# of Votes',
                        data: [12, 19, 3, 5, 2, 3],
                        backgroundColor: [
                        'rgba(255, 99, 132, 0.2)',
                        'rgba(54, 162, 235, 0.2)',
                        'rgba(255, 206, 86, 0.2)',
                        'rgba(75, 192, 192, 0.2)',
                        'rgba(153, 102, 255, 0.2)',
                        'rgba(255, 159, 64, 0.2)'
                            ],
                        borderColor: [
                        'rgba(255, 99, 132, 1)',
                        'rgba(54, 162, 235, 1)',
                        'rgba(255, 206, 86, 1)',
                        'rgba(75, 192, 192, 1)',
                        'rgba(153, 102, 255, 1)',
                        'rgba(255, 159, 64, 1)'
                            ],
                        borderWidth: 1
                    }]
                },
                options:
                {
                    scales:
                    {
                        yAxes: [{
                            ticks:
                            {
                                beginAtZero: true
                            }
                        }]
                    }
                }
            }";

            var chart = JsonConvert.DeserializeObject<ChartJs>(chartData);
            var chartModel = new ChartJsViewModel             {                 Chart = chart,                 ChartJson = JsonConvert.SerializeObject(chart, new JsonSerializerSettings                 {                     NullValueHandling = NullValueHandling.Ignore                 })             };
            return View(chartModel);         }     } }

Our simple ChartJsViewModel only has two members: Chart and ChartJson. I also wanted to take the sample JSON and confirm it deserialized properly into our ChartJs object. 

Models/ChartJsViewModel.cs

public class ChartJsViewModel
{
    public ChartJs Chart { get; set; }
    public string ChartJson { get; set; }
}

With our ViewComponent done, we need the complimentary View to draw our chart.

Views/Shared/Components/ChartJs/default.cshtml

@model ChartJsViewModel

<
div class="chart-container" width="600" height="400">     <canvas id="myChart"></canvas> </div>
<
script>     var ctx = document.getElementById('myChart');     var myChart = new Chart(ctx, @Html.Raw(Model.ChartJson) ); </script>

Our ChartJs component is done. Time to test it out.

Missing Functionality

When I ran the example for the first time, I got a blank section where the chart was supposed to be.

After looking over the code, I forgot the following:

  1. Add the @addTagHelper to the _ViewImports.cshtml
    @addTagHelper *, ChartExample
  2. Add the tag to the Home/Index page (view)
    <vc:chartjs></vc:chartjs>

After adding these two items, I ran the example again and noticed the ViewComponent's View was loading properly, but the JavaScript wasn't executed to display my chart.

After experimenting, I found out we need to wrap our JavaScript with a DOMContentLoaded event listener to make this example work.

@model ChartJsViewModel

<
div class="chart-container" width="600" height="400">     <canvas id="myChart"></canvas> </div>
<
script>     document.addEventListener('DOMContentLoaded', (event) => {
       var ctx = document.getElementById('myChart');         var myChart = new Chart(ctx, @Html.Raw(Model.ChartJson) );
   });
</script>

Our Results

We now have a chart component allowing us to send the data to the client in a Json format to display our interactive chart.

Screenshot of a chart

Conclusion

While this is a very simple demonstration of how to send data from ASP.NET Core to a JavaScript Chart library, you can dig into this further by:

  • Building Other Charts - This is only one bar chart. Build more C# objects based on the examples and documentation provided on the site.
  • Data-Driven Charts - Use Entity Framework to return data for your charts.
  • Various Charting Libraries - ChartJs is just one example. With this model, you can easily create an ASP.NET Core library from any of the Charting libraries from above.
  • KPI Charting - Create dashboard widgets with interactive, dynamic charts to make (hmmm...) ;-)

I hope this provides a better understanding of how to utilize JavaScript charts with ASP.NET Core.

Source code is available at Github.

Do you have a favorite charting library? Is it JavaScript or server-side? Did you write your own? Post your comments below and let's discuss.

ASP.NET 8 Best Practices on Amazon

ASP.NET 8 Best Practices by Jonathan Danylko


Reviewed as a "comprehensive guide" and a "roadmap to excellence" with over 120 Best Practices for ASP.NET Core 8, Jonathan's first book by Packt Publishing explores proven techniques for every phase of the SDLC.

Learn industry-standard concepts to improve your coding, debugging, and deployment of ASP.NET Core websites.

Order now on Amazon.com button

Picture of Jonathan "JD" Danylko

Jonathan "JD" Danylko is an author, web architect, and entrepreneur who's been programming for over 30 years. He's developed websites for small, medium, and Fortune 500 companies since 1996.

He currently works at Insight Enterprises as an Architect.

When asked what he likes to do in his spare time, he replies, "I like to write and I like to code. I also like to write about code."

comments powered by Disqus