CodingCode
CodingCode

Reputation: 123

Running HttpRequest synchronously C#

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

Answers (2)

Gabriel Luci
Gabriel Luci

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

T Karropoulos
T Karropoulos

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

Related Questions