0

I'm working on a UWP project and there's something funky going on with how errors are being presented to me. I don't know if it's VS2017 or how UWP is set up.

I have a piece of code that goes online and retrieves json content, sometimes the code works and sometimes it doesn't. It works when I use Expander control from UWP Community toolkit, and fails when I want to switch to GridView. When it doesn't work, it fails on GetStringAsync method of HttpClient. The strange behavior is that the exception isn't thrown in the method where the problem occurs, the code actually redirects me back without giving an error and as soon as it gets to the property that's supposed to have a value that isn't null, I get a null exception. This is where the problem happens:

string httpContent = "";

using (HttpClient httpClient = new HttpClient())
{
    try
    {
        httpContent = await httpClient.GetStringAsync(uri);
    }
    catch (Exception e)
    {
        // TODO: handle errors
        var x = "";
    }
}

This piece of code is called from within the view model. It starts with a constructor and RefreshServerKanesWrathDataAsync is the method where json is parsed.

public CncOnlinePageViewModel()
{
    cnconline = new CncOnline();
    cnconline.RefreshServerKanesWrathDataAsync();
}

The second I get to GetStringAsync, the code just goes back to the constructor like nothing happened, however the method never completes, it just exits back to the constructor, and therefore fails to update observable collections with data. I then get a null exception.

I wanted to test this with VS2015, but I updated some controls that are apparently only supported withing VS2017, so I can't run the code in other versions.

I also ran into an issue with the code prior to this problem, where I tried to access files in a directory without using a token. The behavior was exactly the same, the code wasn't telling me that I didn't have access to the directory I wanted to read, it was just throwing me out of the method back into the location that made the call to read the directory. Just like with the current problem, I would then run into a null exception, which wasn't where the main problem was.

I added Template10 and UWP community toolkit to the project, if that matters.

Bart
  • 9,925
  • 7
  • 47
  • 64
haosmark
  • 1,097
  • 2
  • 13
  • 27

1 Answers1

3

You shouldn't call an async method from a constructor unless you're willing to provide a callback.

public CncOnlinePageViewModel()
{
    cnconline = new CncOnline();
    var t = cnconline.RefreshServerKanesWrathDataAsync(); // assuming returns Task<string>
    t.ContinueWith(OnCompleted);
}

private void OnCompleted(Task<string> task)
{
    if (task.IsFaulted)
    {
        // Check error
        var exception = task.Exception;
    }
    else if (task.IsCanceled)
    {
        // User hit cancel?
    }
    else
    {
        // All good!
        var result = task.Result;
    }
}

Here's a sample where RefreshServerKanesWrathDataAsync() returns just Task (not Task<result>)

public CncOnlinePageViewModel()
{
    cnconline = new CncOnline();
    var t = cnconline.RefreshServerKanesWrathDataAsync(); // assuming returns Task
    t.ContinueWith(OnCompleted);
}

private void OnCompleted(Task task)
{
    if (task.IsFaulted)
    {
        // Check error
        var exception = task.Exception;
    }
    else if (task.IsCanceled)
    {
        // User hit cancel?
    }
    else
    {
        // All good!
    }
}

On a side note, you may also need to have Visual Studio 2017 break when any exception is thrown. In VS2017, go to Debug->Windows->Exception Settings and make sure Common Language Runtime Exceptions has a check. If it has a filled box, click the box until it turns into a checkmark.

Also..., you can tap into an event raised when any task has an unobserved exception. You can do so in the constructor of App.xaml.cs

public App()
{
   TaskScheduler.UnobservedTaskException += OnUnobservedException;
}

private static void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e)
{
   // Put break point here.
   var ex = e.Exception;

   // This will keep your app alive, but only do it if it's safe to continue.
   e.SetObserved(); 
}
Laith
  • 6,071
  • 1
  • 33
  • 60
  • I made the change, but OnCompleted has a red squiggly, and the error is saying "Argument 1: cannot convert from 'method group' to 'Action' " Any advice on what to do? – haosmark Apr 06 '17 at 02:20
  • Make sure your types match. `private void OnCompleted(Task task)` matches the return type of the `public Task RefreshServerKanesWrathDataAsync()` – Laith Apr 06 '17 at 02:40
  • I added a sample where your method returns just a `Task` not a `Task`. – Laith Apr 06 '17 at 02:45
  • Can't get it work. RefreshServerKanesWrathDataAsync() is a Task method, it just gets some online data and populates a collection with it. I added this signature "private void onCompleted(Task task)" to match what the Refresh method returns like you suggested, and the null exception came back. – haosmark Apr 06 '17 at 02:47
  • Put a breakpoint on the first line of `OnCompleted(Task task)` ... what happens? Does it get hit? – Laith Apr 06 '17 at 02:49
  • It's the same behavior as before, execution breaks once I get to await httpClient.GetStringAsync(uri); – haosmark Apr 06 '17 at 02:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/140022/discussion-between-laith-and-haosmark). – Laith Apr 06 '17 at 02:56