Reputation: 123
I have two functions- let's call them A and B.
I'm trying to make function A wait for function's B result. As well as the parsing at the end of function A to wait for the HTTP Response.
I couldn't figure out how can I get it done since HttpClient
requires Async
work, while I need to avoid it from running on a different thread,
since I need the whole code to wait for the response.
I've tried using a Task return value, converting function B to a class, using await in the response variable and what not. couldn't get it done =(
protected async Task<Dictionary<string, string>> B()
{
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"), "https://example.com/wp-json/wc/v3/products"))
{
var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes("CC"));
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
var response = await httpClient.SendAsync(request);
var contents = await response.Content.ReadAsStringAsync();
dynamic attributes = JsonConvert.DeserializeObject(contents);
Dictionary<string, string> existing = new Dictionary<string, string>();
foreach (var attr in attributes)
{
existing.Add(attr.name, "" + attr.id);
}
return existing;
}
}
}
and Function A:
void A(){
Dictionary<string, string> existingAttr = B();
// Then Does some code with existingAttr
}
The error I'm getting is
System.Collections.Generic.Dictionary.Add(string, string)' ilegal arguments"
Probably because the response wasn't full by that point.
Thanks in advance everyone! 🙃
Upvotes: 0
Views: 114
Reputation: 40858
This:
Dictionary<string, string> existingAttr = B();
Doesn't work because B()
is returning a Task<Dictionary<string, string>>
, not just a Dictionary<string, string>
.
Since this is ASP.NET, there is no reason to make it synchronous. Plus, it would just make trouble. It will. Don't do it.
Make everything async
.
async Task A(){
Dictionary<string, string> existingAttr = await B();
// Then Does some code with existingAttr
}
Make whatever calls A()
async
too and use await A()
, all the way up to the Controller.
Update: Your "illegal arguments" error didn't make sense to me at first, since that kind of error would normally be thrown at compile time. But I looked a little closer and noticed this:
dynamic attributes = JsonConvert.DeserializeObject(contents);
Because attributes
is dynamic
, the compiler doesn't know what actual type it will be until that code is actually run. So your exception happens here:
existing.Add(attr.name, "" + attr.id);
because you're feeding it something that is not a string
. The expression "" + attr.id
will likely come out as a string because of the concatenation. But attr.name
won't be. When you use JsonConver.DeserializeObject
to get a dynamic
object, the actual type of the properties is JValue
, not string
.
You can use .ToString()
:
existing.Add(attr.name.ToString(), attr.id.ToString());
But this is a good example of why you would be better off to create an actual class for your data:
public class MyAttributes {
public string Name {get; set;}
public string Id {get; set;}
}
and deserialize into that type:
var attributes = JsonConvert.DeserializeObject<List<MyAttributes>>(contents);
That way, these kinds of errors get caught at compile time and you don't get nasty surprises later.
Upvotes: 3
Reputation: 61
You can use the await keyword. Await will insert a suspension point in the execution of the method B until the awaited task completes.
Upvotes: 0