Azure ActiveDirectory调用中的任务状态为WaitingForActivation。

3

我对C#中的任务(Tasks)还不是很熟悉。我正在尝试按照示例将ARM模板部署到Azure以启动虚拟机:

https://azure.microsoft.com/zh-cn/documentation/articles/arm-template-deployment/

这里给出的第一个操作之一是通过调用Active Directory来获取授权令牌。链接中给出的代码使用的是AcquireToken api,但该api似乎已被弃用,目前只能找到AcquireTokenAsync。因此,我修改了代码创建了一个任务,并等待其完成:

private static string GetAuthorizationHeader()
{
    ClientCredential cc = new ClientCredential("{application-id}", "{password}");
    var context = new AuthenticationContext("https://login.windows.net/{tenant-id}");

    Task<AuthenticationResult> acquireTokenTask = context.AcquireTokenAsync("https://management.azure.com/", cc);
    Task.WhenAll(acquireTokenTask);
    AuthenticationResult result = acquireTokenTask.Result;
    if (result == null)
    {
      throw new InvalidOperationException("Failed to obtain the JWT token");
    }

    string token = result.AccessToken;

    return token;
}

我原本以为Task.WhenAll会一直阻塞,直到acquireTokenTask的状态变为“RanToCompletion”。但是即使状态是“WaitingForActivation”,WhenAll也不会阻塞,控制权转移到下一个语句,尝试获取acquireTokenTask.Result。这导致了一个异常,其中详细说明有一个发送请求的错误。
问题: 1. 请求发送时是否存在错误,导致状态没有更改为“RanToCompletion”?我认为这不是问题,因为在10次运行中有2-3次成功并且我能够得到结果。 2. 我认为Task.WhenAll会阻塞线程,直到它运行完成。这不是真的吗?如果是,我想知道控制权是如何传递到下一个语句的。 3. 如何解决此问题并在提取结果时每次都获得成功的结果?
1个回答

3
我认为Task.WhenAll会阻塞线程直到它运行完成。这不是真的吗? Task.WhenAll返回一个可等待对象,你需要使用await来等待它。目前,你传递了Task但没有等待,这只会让代码继续执行,直到你使用Task.Result阻塞它。虽然,在这里完全没有必要这样做。 WhenAll用于在有多个任务需要异步等待的情况下使用。在这里,你只需等待单个Task即可:
private static async Task<string> GetAuthorizationHeaderAsync()
{
    ClientCredential cc = new ClientCredential("{application-id}", "{password}");
    var context = new AuthenticationContext("https://login.windows.net/{tenant-id}");

    AuthenticationResult result = await context.AcquireTokenAsync(
                                            "https://management.azure.com/", cc);
    if (result == null)
    {
        throw new InvalidOperationException("Failed to obtain the JWT token");
    }

    string token = result.AccessToken;
    return token;
}

我希望线程阻塞。看起来我需要的是Task.WaitAll。因为如果我使用await,调用线程可能会返回,另一个线程可能会继续工作。如果我错了,请纠正我:Task.WhenAll(taskInstance)== await taskInstance!= Task.WaitAll(taskInstance)。Task.WaitAll会阻塞线程,对吗? - Romonov
@Romonov Task.WhenAll 会异步地让出,而 Task.WaitAll 则会阻塞。但是你为什么要进行阻塞呢?如果您正确地使用 await 整个调用链,应该就可以了。 - Yuval Itzchakov
调用此函数的是Main,而Visual Studio编译器不允许在Main中使用await。因此,我想要阻塞。 - Romonov
@Romonov 好的,那是特殊情况。你可以使用 Task.Result 代替 await - Yuval Itzchakov
这个答案只回答了其中一个问题。从提供的代码来看,应该足够等待调用AcquireTokenAsync。但事实并非如此,仍然会导致问题1中所暗示的问题。我已经正确地将await应用于我的调用,但它仍然在返回的令牌状态为“WaitingForActivation”而不是“RanToCompletion”时继续执行。我只希望我有一个答案,但我必须怀疑AcquireTokenAsync的调用存在故障,它在获取令牌之前就返回了! - Rob Von Nesselrode
@RobVonNesselrode 这个答案回答了所有问题。OP是在询问Task.WhenAll,而不是等待对AcquireTokenAsync的调用。如果您可以访问Token属性,那么这意味着返回的任务已经完成,因此它过早地返回的可能性非常小。 - Yuval Itzchakov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接