I'm writing a service that charts some data. The data is retrieved from blob storage by a client that only has an async Get method to get the data. Once the data is retrieved it is used to populate the chart and this is done using another method Redraw that is also async. I would like the chart to update every minute or so so I have the Get and Redraw called inside a while loop with a delay.
private async Task Redraw(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        var data = await DataProvider.Get();
        await Chart.Redraw(data.Labels, new[] {data.DataSet});
        await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
    }
}
Unfortunately, this fails. I get a NullReferenceException and a AggregateException from somewhere in the chart library. Modifying the code as follows does work.
private async Task Redraw(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        var data = Task.Run(() => DataProvider.Get()).GetAwaiter().GetResult();
        await Task.WhenAll(Chart.Redraw(data.Labels, new[] {data.DataSet}));
        await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
    }
}
I'm not sure why the first version using async/await fails. I believe that it's because the Redraw is trying to run before the data task is finished but I also believed that awaiting the Get method would mean that Redraw would not be called until the data task was complete. When I debug those lines the data does appear to be populated before the next line is executed so i'm a bit confused.
Exception thrown: 'System.NullReferenceException' in Blazorise.Charts.dll Exception thrown: 'System.NullReferenceException' in System.Private.CoreLib.dll 'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Diagnostics.StackTrace.dll'. 'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Reflection.Metadata.dll'. 'iisexpress.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.1\System.Collections.Immutable.dll'. Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer: Warning: Unhandled exception rendering component: Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object. at Blazorise.Charts.JS.ToChartDataSet[T](ChartData
1 data) at Blazorise.Charts.JS.InitializeChart[TItem,TOptions](IJSRuntime runtime, DotNetObjectReference1 dotNetObjectReference, Boolean hasClickEvent, Boolean hasHoverEvent, String canvasId, ChartType type, ChartData1 data, TOptions options, String dataJsonString, String optionsJsonString) at Blazorise.Charts.BaseChart4.Initialize()
at Blazorise.Charts.BaseChart`4.OnAfterRenderAsync(Boolean firstRender) Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost: Error: Unhandled exception in circuit 'v_kcV7GT8jgmXOLCuNjM_i918pfAqsaPh5KVrAsZNUw'.System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.) ---> System.NullReferenceException: Object reference not set to an instance of an object. at Blazorise.Charts.JS.ToChartDataSet[T](ChartData
1 data) at Blazorise.Charts.JS.InitializeChart[TItem,TOptions](IJSRuntime runtime, DotNetObjectReference1 dotNetObjectReference, Boolean hasClickEvent, Boolean hasHoverEvent, String canvasId, ChartType type, ChartData1 data, TOptions options, String dataJsonString, String optionsJsonString) at Blazorise.Charts.BaseChart4.Initialize()
at Blazorise.Charts.BaseChart`4.OnAfterRenderAsync(Boolean firstRender) --- End of inner exception stack trace ---
I'm digging deeper and I don't think the null reference is being throw when calling Chart.Redraw at all. When this line executes the data is not null. Instead it looks like it is related somehow to async/await. The call that precedes Redraw looks like this..
protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (!_isAlreadyInitialized && firstRender)
    {
        _isAlreadyInitialized = true;
        await Redraw(_cancellationToken);
    }
}
This overrides the method of the base class from the library. The base class implementation is as follows..
protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    await this.Initialize();
  else
    await this.Update();
}
It is this call to Initialize which is calling another method..
private static object ToChartDataSet<T>(ChartData<T> data)
{
  return (object) new
  {
    Labels = data.Labels,
    Datasets = ((IEnumerable<object>) data.Datasets).ToList<object>()
  };
}
..and it's here where the data is null.
For some reason using await/async in the Redraw method results in the base class calling Initialize => ToChartDataSet before the call to DataProvider.Get is complete. When using GetAwaiter().GetResult() then Initialize is not called until the DataProvider.Get has completed. 
