请求令牌时跳过代码执行

Code execution skipped while requesting for token

我正在请求令牌,但代码未在 SendAsync 部分执行。我正在成功使用邮递员获取令牌。

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);

我什至在没有 ["Content-Type"] = "application/x-www-form-urlencoded" 的情况下尝试过,但对我不起作用。

更新

事实证明,'skipping' 方法其余部分的实际原因是意外地没有等待父方法中对 GetSpeechServiceToken 的调用。这导致线程继续在原始线程上执行并跳出该方法,似乎跳过了其余部分。

OP 通过这样调用它来修复此问题:GetSpeechServiceToken().Wait() 而不是 GetSpeechServiceToken()

如果您 运行 遇到类似的问题,下面是微软的一些有趣读物,其中更详细地介绍了使用 async/await 进行异步编程。

This article更详细地解释了这个概念,下面是摘录

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.

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

原答案

它不起作用的原因是你没有正确调用端点:

您可以使用以下任一端点:

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

请求可以是这样的:

            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();

结果已经是带有标记值的字符串。不需要用 Json.Net 反序列化它,那只会导致异常。