0

I want to call an async Web Service method from inside an async method and user a WPF Window in order to ask the user for the username and Password.

The Code Looks similar to this:

private async Task GetUsers()
{
        List<User> users = new List<User>();

        using (var client = new HttpClient())
        {
            var authenticationWindow = new AuthenticateWindow();
            authenticationWindow.ShowDialog();

             //... Code to get the token ...
            var token = "myToken";

            client.BaseAddress = new Uri("http://localhost:56057/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);

            var response = await client.GetAsync("api/users/");

            if (response.IsSuccessStatusCode)
            {
                users = await response.Content.ReadAsAsync<List<User>>();
            }
            else if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                throw new UnauthorizedAccessException();
            }
        }

        foreach(var user in users)
        {
        }
}

If I execute this Code I get the following exception:

An unhandled exception of type 'System.NullReferenceException' occurred in PresentationFramework.dll

This happens when calling client.GetAsync("api/users/"). It has probably something to do with context switching happenening because I opened the window.

How can I solve this Problem?

The call stack just Shows "External Code".

If I remove the following two lines everything works fine:

var authenticationWindow = new AuthenticateWindow();
authenticationWindow.ShowDialog();
Alexander
  • 1,021
  • 6
  • 20
  • 38

1 Answers1

2

You have a UI element being instantiated and used within the scope of a service, try to instead separate these two from each-other. It sounds like you need to have this logic of requesting users in the AuthenticateWindow, perhaps on its Loaded event:

// Safe UI entry point for async work, i.e.; event handler.
async void OnLoaded(object sender, RoutedEventArgs e)
{
    var users = await GetUsersAsync();
    // Take action on the user's from the API.
}

And then have the GetUsers (renamed more appropriately to GetUsersAsync) focus only on consuming the HttpClient and corresponding API, materializing and returning the List<User> like so:

async Task<List<User>> GetUsersAsync()
{
    List<User> users = new List<User>();

    using (var client = new HttpClient())
    {
         //... Code to get the token ...
        var token = "myToken";

        client.BaseAddress = new Uri("http://localhost:56057/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);

        var response = await client.GetAsync("api/users/");

        if (response.IsSuccessStatusCode)
        {
            users = await response.Content.ReadAsAsync<List<User>>();
        }
        else if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            throw new UnauthorizedAccessException();
        }
    }
    return users;
}
David Pine
  • 23,787
  • 10
  • 79
  • 107