Search code examples
c#jsonjson.netfile-read

Async Deserialization call not working in C#


I am using Newtonsoft.Json for reading a json file. I am trying to make a aysnc call to the json file to read its data but unfortunately it's not returning anything. I tried without async and it works perfectly, following is my code:

public static async Task<T> LoadAsync<T>(string filePath)
{
        // filePath: any json file present locally on the disk
        string basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\", "");
        string fullPath = Path.Combine(basePath, filePath);
        using (var stream = File.OpenRead(fullPath))
        {
            var reader = new StreamReader(stream, Encoding.GetEncoding("iso-8859-1"));
            var task = Task.Factory.StartNew(() => JsonConvert.DeserializeObject<T>(reader.ReadToEnd()));
            var value = await task;
            return value;
        }
}

I tried to debug but debugger is not coming on "return value" in the above method and I am calling above method by following function:

private void GetDataFromJson()
{
        var value = JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE);
}

What can be the problem ? File is present locally on my computer.


Solution

  • I am trying to make a aysnc call to the json file to read its data

    Do you really want to make the code asynchronously? Does the JsonUtilities class offer a synchronous version of the LoadAsync() method?

    Your method is synchronous:

    private void GetDataFromJson()
    {
            var value = JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE);
    }
    

    It does exactly one thing: it calls LoadAsync(). It does store the return value of that method in value, but you never use value. So it's ignored. The return value of LoadAsync() is not the TaxOffice object. It's a Task that represents the work LoadAsync() is doing. Until that task is done, there's no way to get a value. But GetDataFromJson() doesn't wait for the task to be done. So if the caller expects it to be done by the time the method returns, it's going to be sorely disappointed.

    How best to fix your code is unclear, as you haven't provided a good, minimal, complete code example showing what you need help with. But there are two obvious strategies you can follow:

    Make the method asynchronous:

    private async Task GetDataFromJson()
    {
            var value = await JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE);
    
            // presumably you do something with "value" here?
    }
    

    This is the best approach. But it will require that the caller be able to correctly deal with an asynchronous call. It will likely need to be turned into an async method as well. And its caller. And so on, until you get to the top of your call stack (e.g. an event handler method).

    It's a bit of a pain to switch to async throughout your call stack, but the code will work much better if you do. Your thread (probably a UI thread) won't get stuck waiting on the operation, and you'll be all set to correctly deal with other asynchronous operations as well.

    Ignore the asynchronous nature of the LoadAsync() method:

    private void GetDataFromJson()
    {
            var value = JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE).Result;
    
            // presumably you do something with "value" here?
    }
    

    This is the Not Very Good™ approach. It works. But it holds up your current thread until the asynchronous operation is done, negating the entire benefit of having an asynchronous operation in the first place.