1

I am trying to access the JSON response that the following code should generate:

public static async Task<string> GetResponseString(string refreshToken)
    {
        var client = new HttpClient();
        client.BaseAddress = new Uri("https://www.strava.com");
        var request = new HttpRequestMessage(HttpMethod.Post, "/oauth/token");

        var keyValues = new List<KeyValuePair<string, string>>();
        keyValues.Add(new KeyValuePair<string, string>("client_id", "some_id"));
        keyValues.Add(new KeyValuePair<string, string>("client_secret", "some_secret"));
        keyValues.Add(new KeyValuePair<string, string>("refresh_token", refreshToken));
        keyValues.Add(new KeyValuePair<string, string>("grant_type", "refresh_token"));

        request.Content = new FormUrlEncodedContent(keyValues);
        var response = await client.SendAsync(request);
        var result = await response.Content.ReadAsStringAsync();

        return result;
    }

The expected result looks like this.

    {
  "token_type": "Bearer",
  "access_token": "a9b723...",
  "expires_at":1568775134,
  "expires_in":20566,
  "refresh_token":"b5c569..."
}

When doing this in Postman or Javscript the result is correct, so I guess I am not capable of accessing the task string in a correct manner :-)

Any help pointing me in the right direction will be much appreciated.

Thnx

iAyAy
  • 39
  • 6
  • 4
    You show your code which looks ok but you don't show how you are consuming this code. If it's returning a task and you aren't awaiting the result then you need to do so. The result property of the task will contain the JSON. – Charleh Jul 11 '20 at 15:58
  • @Charleh I am calling it using `var result = collection.GetResponseString("some_token");` – iAyAy Jul 11 '20 at 16:00
  • 1
    Right so you need to await the result, the task is async, it runs asynchronously so execution will continue unless you await the result. You can call `GetAwaiter().GetResult()` to block the current thread until the async task completes and return the result of the task. `GetResponseString().GetAwaiter().GetResult()`, though you might also want to check if the result was successful etc. – Charleh Jul 11 '20 at 16:04
  • Bear in mind, it's much better to await the result due to potential deadlocks, https://stackoverflow.com/questions/17284517/is-task-result-the-same-as-getawaiter-getresult though in your case you might be ok, it depends on what's calling the method. – Charleh Jul 11 '20 at 16:07
  • Thanks you @Charleh The request just times out now however. I was under the impression that I was already waiting for the result using `var result = await response.Content.ReadAsStringAsync();` So the `.GetAwaiter().GetResult()` should not be necessary ? – iAyAy Jul 11 '20 at 17:45
  • Even if you await it in the async method, if the caller is not async you just get a task back which has to be awaited – Charleh Jul 12 '20 at 12:03

1 Answers1

2

Your code contains more than one mistake.

Did you see HttpClient documentation?
Do you know about IDisposable?
Do you know that collection of KeyValuePair is Dictionary?

Don't use var keyword if you're not absolutely sure what are you doing. var can hide original problem from you and your question is example how var kills your time. I recommend using explicit types where possible.

And yes, as maintained above in comments you must unwrap string result from awaitable Task with await.

private static readonly HttpClient client = new HttpClient();

private static async Task<string> GetResponseStringAsync(string url, Dictionary<string, string> formData)
{
    using (HttpContent content = new FormUrlEncodedContent(formData))
    using (HttpResponseMessage response = await client.PostAsync(url, content))
    {
         response.EnsureSuccessStatusCode();
         return await response.Content.ReadAsStringAsync();
    }
}

Usage

Dictionary<string, string> postData = new Dictionary<string, string>();
postData.Add("client_id", "some_id");
postData.Add("client_secret", "some_secret");
postData.Add("refresh_token", refreshToken);
postData.Add("grant_type", "refresh_token");

try
{
    string result = await GetResponseStringAsync("https://www.strava.com/oauth/token", postData);
    // success here
}
catch (Exception ex)
{
    Debug.WriteLine(ex.Message);
    // request failed
}

And finally, time to say Hello to Asynchronous programming. :)

aepot
  • 4,558
  • 2
  • 12
  • 24
  • Thank you so much for the code suggestion. I have read the doc about HttpClient, I am however not a native C# programmer, but fluent in front end development. This is just a hobby project for myself. The `return await response.ReadAsStringAsync();` should be `return await response.Content.ReadAsStringAsync();` Right? – iAyAy Jul 12 '20 at 16:28
  • The `string result = await GetResponseStringAsync("https://www.strava.com/oauth/token", postData);` fails as await can only be used within a async method? – iAyAy Jul 12 '20 at 16:30
  • @iAyAy 1) fixed, exactly, thanks! 2) yes, the caller method must be `async` – aepot Jul 12 '20 at 16:32
  • @iAyAy what kind of app? Can you show the caller method? Maybe i can help. – aepot Jul 12 '20 at 17:00