【问题标题】:ExecuteAsync doesn't return control to the debuggerExecuteAsync 不会将控制权返回给调试器
【发布时间】:2020-12-09 02:31:57
【问题描述】:

我正在尝试使用 MSAL.NET 获取令牌,并且几乎使用了他们的开箱即用教程代码。

using Microsoft.Identity.Client;
using MyApp.Interfaces;
using System;
using System.Threading.Tasks;

namespace MyApp.NetworkServices
{
    public class MyAuthorizationClient : IMyAuthorizationClient
    {
        private readonly string[] _resourceIds;
        private IConfidentialClientApplication App;

        public MyAuthorizationClient(IMyAuthenticationConfig MyAuthenticationConfig)
        {
            _resourceIds = new string[] { MyAuthenticationConfig.MyApimResourceID };

            App = ConfidentialClientApplicationBuilder.Create(MyAuthenticationConfig.MyApimClientID)
                .WithClientSecret(MyAuthenticationConfig.MyApimClientSecret)
                .WithAuthority(new Uri(MyAuthenticationConfig.Authority))
                .Build();
        }

        public async Task<AuthenticationResult> GetMyAccessTokenResultAsync()
        {
            AuthenticationResult result = null;

            try
            {
                result = await App.AcquireTokenForClient(_resourceIds).ExecuteAsync().ConfigureAwait(continueOnCapturedContext:false);
            }
            catch(MsalClientException ex)
            {
                ...
            }
            return result;            
    }
}

}

我遇到的问题是在await 调用中,它永远不会返回。调试器不会恢复控制,应用程序会进入前台,就好像它继续运行一样。我无法查询result 的结果,并且我已经将await 配置为不继续。

我查看了这个很棒的帖子,但没有为我的场景找到任何解决方案:Async call with await in HttpClient never returns

【问题讨论】:

  • 我正在努力解决完全相同的问题。我能够在 ApplicationBuilder 上使用 WithLogging() 并输出到文件以至少获取一些日志记录,但它总是在“从主机 login.microsoftonline.com 的网络中获取实例发现”时死掉。无法弄清楚实际的根本原因是什么,但也许这将有助于您进一步诊断您的问题。
  • 通过使用 .ExecuteAsync().Result 没有等待,我能够让它抛出异常而不是使调试器崩溃,这导致它实际评估并给我一些回报。似乎我的范围是错误的,但不知道为什么。

标签: c# .net concurrency async-await msal


【解决方案1】:

您的代码:

try
{
    result = await App.AcquireTokenForClient(_resourceIds).ExecuteAsync().ConfigureAwait(continueOnCapturedContext:false);
}

移除 await 并使用 .Result 而不是 .ConfigureAwait():

try
{
    result = App.AcquireTokenForClient(_resourceIds).ExecuteAsync().Result;
}

当我这样做时,调试器实际上捕获了一个异常,而不是突然关闭。对于我的情况,原来我的范围(又名代码中的 _resourceIds)是错误的。实际适用于我的用例的范围:

private string[] Scopes = new[]
{
    "https://graph.microsoft.com/.default"
};

【讨论】:

  • “删除异步并使用 .Result 而不是 .ConfigureAwait():” - 这是可怕的,糟糕的建议,IMO
  • @MarcGravell 这真是无用的评论。请随时提供一个可行的解决方案。我知道 .Result 是一个不好的做法,但这解决了我的问题并可能解决 OPs 问题。我是否应该将我的代码恢复到仅遵循最佳实践而没有任何作用的状态?如果 ExecuteAsync 无需附加 ConfigureAwait 或使用 Result 即可工作,我会很高兴,但它根本不在 Microsoft 自己提供的示例代码中。
  • 您的代码有效,但当我添加一个通用的Exception catch 块时,原始代码也有效。这个例外也和你的一模一样。谢谢
  • @8protons 很高兴它为你解决了!不幸的是,就我而言,根本没有抛出异常,调试器在运行该行时自行终止,没有任何错误。
  • @MarcGravell @Chartreugz 使用此示例代码docs.microsoft.com/en-us/exchange/client-developer/… 我遇到了同样的问题,即使遇到了一般Exception。通过在单独的 try catch 中调用 AcquireTokenForClient 并删除 await 并使用 .Result,现在可以正常工作 - 没有其他任何更改。
【解决方案2】:

问题是我没有发现一般异常。以下让我发现了我的问题,即我没有正确的范围:

public async Task<AuthenticationResult> GetMyAccessTokenResultAsync()
{
    AuthenticationResult result = null;

    try
    {
        result = await App.AcquireTokenForClient(_resourceIds).ExecuteAsync();
    }
    catch(MsalClientException ex)
    {
        ...
    }
    catch(Exception ex)
    {
        ...
    }

    return result;            
}

【讨论】:

  • 我像你的一样尝试并捕获,但它没有捕获任何错误。只是用结果替换 async 对我有用,没有发现错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多