首页 > 解决方案 > 请求令牌时跳过代码执行

问题描述

我正在请求令牌,但代码未按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"但对我不起作用。

标签: c#azure-cognitive-services

解决方案


更新

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

OP 解决了这个问题,而是像这样调用它:GetSpeechServiceToken().Wait()而不是GetSpeechServiceToken()

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

这篇文章更详细地解释了这个概念,下面是摘录

异步方法中发生了什么

在异步编程中要理解的最重要的事情是控制流如何从一个方法移动到另一个方法。下图将引导您完成整个过程。

异步流示例

图中的数字对应于以下步骤。

  1. 事件处理程序调用并等待AccessTheWebAsync异步方法。

  2. AccessTheWebAsync创建一个HttpClient实例并调用 GetStringAsync异步方法以字符串形式下载网站内容。

  3. 发生了一些事情GetStringAsync,暂停了它的进展。也许它必须等待网站下载或其他一些阻止活动。为了避免阻塞资源,GetStringAsync将控制权交给调用者,AccessTheWebAsync.

    GetStringAsync返回一个Task<TResult>whereTResult是一个字符串, AccessTheWebAsync并将任务分配给getStringTask变量。该任务表示对 的调用的正在进行的过程GetStringAsync,并承诺在工作完成时产生一个实际的字符串值。

  4. 因为getStringTask还没有等待,AccessTheWebAsync所以可以继续其他不依赖于最终结果的工作 GetStringAsync。该工作由对同步方法的调用表示DoIndependentWork

  5. DoIndependentWork是一个同步方法,它完成它的工作并返回给它的调用者。

  6. AccessTheWebAsync如果没有getStringTask. AccessTheWebAsyncnext 想要计算并返回下载的字符串的长度,但是该方法无法计算该值,直到该方法具有该字符串。

    因此,AccessTheWebAsync使用 await 运算符来暂停其进度并将控制权交给调用的方法 AccessTheWebAsyncAccessTheWebAsync将 a 返回Task<int>给调用者。该任务代表了一个承诺,即产生一个整数结果,该结果是下载字符串的长度。

    在调用者(本例中的事件处理程序)内部,处理模式继续进行。调用者可能会在等待结果之前执行不依赖于结果的其他工作AccessTheWebAsync,或者调用者可能会立即等待。事件处理程序正在等待 AccessTheWebAsync,并且AccessTheWebAsync正在等待 GetStringAsync

  7. GetStringAsync完成并产生一个字符串结果。调用不会以GetStringAsync您可能期望的方式返回字符串结果。(请记住,该方法已经在步骤 3 中返回了一个任务。)相反,字符串结果存储在表示方法完成的任务中,getStringTask. await 运算符从 中检索结果getStringTask。赋值语句将检索到的结果赋值给urlContents.

  8. AccessTheWebAsync有字符串结果时,该方法可以计算字符串的长度。然后 的工作AccessTheWebAsync也完成了,等待的事件处理程序就可以恢复了。

微软发表的另一篇关于 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 对其进行反序列化,这只会导致异常。


推荐阅读