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 Answers
Reset to default 1If 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
andWait
- in your case you need to goasync
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.
Wait()
at all ever. Instead use a callback (event) like OnLoad , make the handler async and await the call toGet_Place
. There's more but that should get you started, at least. – Fildor Commented Jan 22 at 15:00