admin管理员组

文章数量:1318012

I need to program a query of an API interface in my C# program. When I query the interface via the browser with https://URI//api/clientnetwork/, I get a corresponding response; initially it's only

{
  “errors": [
    “Invalid API key”
  ]
}

because the API key is still missing, but I would like to get at least that far in my program.

This is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ApiRequest
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Get_Place("").Wait();
        }

        static async Task Get_Place(string ip)
        {
            string path = "https://URI";

            try
            {
                using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri(path);

                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                    MessageBox.Show(path, "Path"); //Debug
                    HttpResponseMessage response = await client.GetAsync("api/clientnetwork");
                    MessageBox.Show("fertig", "fertig"); //Debug

                    if (response.IsSuccessStatusCode)
                    {
                        var jsonstring = response.Content.ReadAsStringAsync();
                        jsonstring.Wait();

                        //sto = JsonConvert.DeserializeObject<Standort>(jsonstring.Result);
                        MessageBox.Show(jsonstring.ToString(), "Rückgabewert"); //Debug
                        //sto = await response.Content.ReadAsAsync<Standort>(); - ReadAsAsync geht nicht
                    }
                    else
                    {
                        MessageBox.Show(response.StatusCode.ToString(), "Rückgabecode"); //Debug
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Fehler:");
            }
        }
    }
}

My program hangs at the point where it executes the

HttpResponseMessage response = await client.GetAsync("api/clientnetwork"); 

call, or it seems to wait forever for a response. What am I doing wrong?

I need to program a query of an API interface in my C# program. When I query the interface via the browser with https://URI//api/clientnetwork/, I get a corresponding response; initially it's only

{
  “errors": [
    “Invalid API key”
  ]
}

because the API key is still missing, but I would like to get at least that far in my program.

This is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ApiRequest
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Get_Place("").Wait();
        }

        static async Task Get_Place(string ip)
        {
            string path = "https://URI";

            try
            {
                using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri(path);

                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                    MessageBox.Show(path, "Path"); //Debug
                    HttpResponseMessage response = await client.GetAsync("api/clientnetwork");
                    MessageBox.Show("fertig", "fertig"); //Debug

                    if (response.IsSuccessStatusCode)
                    {
                        var jsonstring = response.Content.ReadAsStringAsync();
                        jsonstring.Wait();

                        //sto = JsonConvert.DeserializeObject<Standort>(jsonstring.Result);
                        MessageBox.Show(jsonstring.ToString(), "Rückgabewert"); //Debug
                        //sto = await response.Content.ReadAsAsync<Standort>(); - ReadAsAsync geht nicht
                    }
                    else
                    {
                        MessageBox.Show(response.StatusCode.ToString(), "Rückgabecode"); //Debug
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Fehler:");
            }
        }
    }
}

My program hangs at the point where it executes the

HttpResponseMessage response = await client.GetAsync("api/clientnetwork"); 

call, or it seems to wait forever for a response. What am I doing wrong?

Share Improve this question edited Jan 27 at 9:35 CommunityBot 11 silver badge asked Jan 22 at 14:57 LarianLarian 431 silver badge5 bronze badges 4
  • 2 You cannot do it that way. Don't call this method in the ctor and don't call Wait() at all ever. Instead use a callback (event) like OnLoad , make the handler async and await the call to Get_Place. There's more but that should get you started, at least. – Fildor Commented Jan 22 at 15:00
  • 2 This code looks like it "might be" WPF. Consider adding a tag please. – IV. Commented Jan 22 at 15:17
  • If it is WPF, not WinForms, above comment still holds with minor adjustments. The "don't"s definitely still apply. And "don't call Wait() at all ever" ... except you know exactly what and why you are doing .. yadda .. for now and probably a fair amount of time into the future: just don't. I haven't had to in pretty much since async / Task went onto my radar. – Fildor Commented Jan 22 at 15:19
  • you're right, added this tag - thank you for the hint, used some tutorials and therefore came to this problem, i don't have many experiences at this point – Larian Commented Jan 24 at 7:02
Add a comment  | 

2 Answers 2

Reset to default 1

If it is WPF, the Loaded event will help you achieve your objective.

The solution will be to await the HTTP GET, and since the constructor itself can't be async you will have to respond to an event like Loaded instead. Using inline syntax to declare the event handler in the constructor is one way to state your intention. But to be clear, this is a deferred action that isn't going to perform any IO while the ctor is actually executing.

public MainWindow()
{
    InitializeComponent();
    Loaded += async (sender, e) =>
    {
        var response = await Get_Place("https://catfact.ninja/facts?limit=1");
        MessageBox.Show(response, "Http Response");
    };
}

I wanted to test this answer, so I posted an HTTP request to try it out. Here's the mimimal example I used to test it.

/// <summary>
/// A working HTTP interaction for this example
/// </summary>
async Task<string?> Get_Place(string ip)
{
    string? mockResponse = null;
    using (HttpClient client = new HttpClient())
    {
        try
        {
            HttpResponseMessage response = await client.GetAsync(ip);

            if (response.IsSuccessStatusCode)
            {
                string json = await response.Content.ReadAsStringAsync();
                // NOTE: This line will depend on how your content is formatted.
                mockResponse = JObject.Parse(json)["data"]?[0]?["fact"]?.ToString();
            }
            else
            {
                Debug.WriteLine($"Failed to fetch. Status code: {response.StatusCode}");
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"An error occurred: {ex.Message}");
        }
    }
    return mockResponse;
}

By calling Wait() you are blocking current thread by synchornously waiting for the Task.

When you hit first async, it then goes to other thread to do asynchronous work. Then, when continuation of the method (after await) tried to run on the thread that is blocked at Wait() call.

And you get a deadlock. That's why await should not be mixed with synchronous Wait calls.

Minimal reporduction:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Console.WriteLine("Calling Get_Data");
        Get_Data().Wait();
    }

    private static async Task Get_Data()
    {
        Debug.WriteLine("Before LongRunningCallAsync");
        await LongRunningCallAsync();
        Debug.WriteLine("Awaited LongRunningCallAsync, before OtherLongRunningCallAsync");
        OtherLongRunningCallAsync().Wait();
        Debug.WriteLine("Waited for OtherLongRunningCallAsync");
    }

    private static async Task LongRunningCallAsync()
    {
        await Task.Delay(1000);
    }

    private static async Task OtherLongRunningCallAsync()
    {
        await Task.Delay(1000);
    }
}

If you remove all async calls and use Wait all the way through, it will work.

But as correctly pointed, you should correctly handle async operation in this scenario.

I think Async and Await by Stephen Cleary became one of the most popular posts on the topic. You should read it :)

EDIT

After reading, it should be more clear that:

  • don't mix await and Wait - in your case you need to go async all the way
  • constructors cannot be async, so move that into event handler, as already suggested (like OnLoad)
  • only exception for async void is for event handlers, which only advocates for using event to perform your asynchronous work.

本文标签: cDon39t get an answer from my API requestmy program is waitingStack Overflow