Search code examples
c#azure-cognitive-services

Code execution skipped while requesting for token


I am requesting for token but code doesn't executed on SendAsync portion. I am getting token usisng postman successfully.

Here is the example snippet:

                string tokenUrl = $"https://myServiceUrl.cognitiveservices.azure.com/sts/v1.0/issuetoken";
                var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
                tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    ["Content-Type"] = "application/x-www-form-urlencoded",
                    ["Ocp-Apim-Subscription-Key"] = "MyKey"
                });
                HttpClient client = new HttpClient();

                var tokenResponse = await client.SendAsync(tokenRequest); // skipped here 

                dynamic json = await tokenResponse.Content.ReadAsStringAsync();
                var token = JsonConvert.DeserializeObject<string>(json);

I even tried without ["Content-Type"] = "application/x-www-form-urlencoded" but doesn't work for me.


Solution

  • Update

    It turns out the actual cause for 'skipping' the rest of the method was accidentally not awaiting the call to GetSpeechServiceToken in the parent method. This caused the thread execution to continue on the original thread and step out of the method, seemingly skipping the remainder.

    OP fixed this by instead calling it like this: GetSpeechServiceToken().Wait() instead of GetSpeechServiceToken()

    If you run into a similar issue, below are some interesting reads by microsoft that go into more detail about asynchronous programming with async/await.

    This article explain the concept in more detail, below is an excerpt

    What Happens in an Async Method

    The most important thing to understand in asynchronous programming is how the control flow moves from method to method. The following diagram leads you through the process.

    Example of Async Flow

    The numbers in the diagram correspond to the following steps.

    1. An event handler calls and awaits the AccessTheWebAsync async method.

    2. AccessTheWebAsync creates an HttpClient instance and calls the GetStringAsync asynchronous method to download the contents of a website as a string.

    3. Something happens in GetStringAsync that suspends its progress. Perhaps it must wait for a website to download or some other blocking activity. To avoid blocking resources, GetStringAsync yields control to its caller, AccessTheWebAsync.

      GetStringAsync returns a Task<TResult> where TResult is a string, and AccessTheWebAsync assigns the task to the getStringTask variable. The task represents the ongoing process for the call to GetStringAsync, with a commitment to produce an actual string value when the work is complete.

    4. Because getStringTask hasn't been awaited yet, AccessTheWebAsync can continue with other work that doesn't depend on the final result from GetStringAsync. That work is represented by a call to the synchronous method DoIndependentWork.

    5. DoIndependentWork is a synchronous method that does its work and returns to its caller.

    6. AccessTheWebAsync has run out of work that it can do without a result from getStringTask. AccessTheWebAsync next wants to calculate and return the length of the downloaded string, but the method can't calculate that value until the method has the string.

      Therefore, AccessTheWebAsync uses an await operator to suspend its progress and to yield control to the method that called AccessTheWebAsync. AccessTheWebAsync returns a Task<int> to the caller. The task represents a promise to produce an integer result that's the length of the downloaded string.

      Inside the caller (the event handler in this example), the processing pattern continues. The caller might do other work that doesn't depend on the result from AccessTheWebAsync before awaiting that result, or the caller might await immediately. The event handler is waiting for AccessTheWebAsync, and AccessTheWebAsync is waiting for GetStringAsync.

    7. GetStringAsync completes and produces a string result. The string result isn't returned by the call to GetStringAsync in the way that you might expect. (Remember that the method already returned a task in step 3.) Instead, the string result is stored in the task that represents the completion of the method, getStringTask. The await operator retrieves the result from getStringTask. The assignment statement assigns the retrieved result to urlContents.

    8. When AccessTheWebAsync has the string result, the method can calculate the length of the string. Then the work of AccessTheWebAsync is also complete, and the waiting event handler can resume.

    Another article published by microsoft about best practices for async/await

    Original Answer

    The reason it does't work is because your not calling the endpoint correctly:

    You can use either of these endpoints:

    https://api.cognitive.microsoft.com/sts/v1.0/issueToken https://myServiceUrl.cognitiveservices.azure.com/sts/v1.0/issuetoken

    And the request can be like this:

                var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
                tokenRequest.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
    
                var client = new HttpClient();
    
                var tokenResponse = await client.SendAsync(tokenRequest);
    
                var result = await tokenResponse.Content.ReadAsStringAsync();
    

    The result is already a string with the token value. No need to deserialize it with Json.Net, that'll just cause an exception.