MS Graph Client AcquireTokenForClient调用在.Net 4.8 + XAML应用程序中永远不会返回

oipij1gg  于 2023-05-27  发布在  .NET
关注(0)|答案(1)|浏览(130)

我有一个MS图形客户端创建代码,我从另一个应用程序(.NET 4.6.2)复制过来,它可以完美地工作,进入一个使用XAML作为UI的.NET 4.8应用程序。

public Microsoft365(BaseSource source)
        : base(source)
    {
        _ = GetGraphClient().GetAwaiter().GetResult();
    }

    /// <summary>
    /// Generates a MS Graph Client based on the OAuth2 Token Data supplied via <see cref="BaseSource"/>
    /// </summary>
    /// <returns></returns>
    private async Task<GraphServiceClient> GetGraphClient()
    {
        try
        {
            if (_graphClient != null)
            {
                return _graphClient;
            }

            var clientId = "<redacted>";
            var tenantId = "<redacted>";
            var clientSecret = "<redacted>";

            var scopes = new List<string> { "https://graph.microsoft.com/.default" };

            var app = ConfidentialClientApplicationBuilder.Create(clientId)
                .WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
                .WithClientSecret(clientSecret)
                .Build();

            var authResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();
            var token = authResult.AccessToken;

            ClientSecretCredential clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);

            var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
            _graphClient = graphClient;

            return graphClient;
        }

        catch (MsalException msalException)
        {
            // Handle MSAL exceptions
            Console.WriteLine($"MSAL Exception: {msalException.Message}");
            // Additional handling or logging can be added here
        }
        catch (ServiceException serviceException)
        {
            // Handle Graph API exceptions
            Console.WriteLine($"Graph API Exception: {serviceException.Message}");
            // Additional handling or logging can be added here
        }
        catch (Exception ex)
        {
            // Handle other exceptions
            Console.WriteLine($"Exception: {ex.Message}");
            // Additional handling or logging can be added here
        }

        return null;
    }

在添加新DMS源并按下XAML UI中的保存按钮并移交到BaseSource接口的构造函数之后,将调用此代码。
一切正常,直到:var authResult = await app.AcquireTokenForClient(_scopes).ExecuteAsync();
这个电话需要很长时间,似乎永远不会回来,直到最终(超过10分钟+)。没有一个异常检查点被命中。
我得到的问候是:托管调试助手'DisconnectedContext'Message=Managed Debugging Assistant 'DisconnectedContext' : 'Folgender Fehler beim Übergang in den COM-Kontext 0x537ae6a8 für diesen RuntimeCallableWrapper: Systemaufruf ist fehlgeschlagen. (Ausnahme von HRESULT: 0x80010100 (RPC_E_SYS_CALL_FAILED)). Dieser tritt in der Regel auf, da der COM-Kontext 0x537ae6a8, in dem dieser RuntimeCallableWrapper erstellt wurde, getrennt wurde oder aufgrund eines anderen Vorgangs ausgelastet ist. Die Schnittstellen werden aus dem aktuellen COM-Kontext (COM-Kontext 0x537ae7d0) freigegeben. Dies kann Datenbeschädigung oder -verlust zur Folge haben. Um dieses Problem zu vermeiden, müssen Sie sicherstellen, dass alle COM-Kontexte/Apartments/Threads so lange beibehalten werden und für den Kontextübergang verfügbar sind, bis die Anwendung alle RuntimeCallableWrappers, die in ihnen enthaltene COM-Komponenten darstellen, vollständig verarbeitet hat.'和VS 22中的中断模式选项卡。
完全相同的代码在.Net 4.6.2控制台程序和.Net 4.8控制台程序中工作。我已经交叉检查了barebones .net 4.8项目和.net 4.8 xaml项目之间的所有NuGet包,它们完全相同。
唯一的未决问题是XAML UI中的13个绑定问题,我认为这无关紧要--因为它们只针对可见性属性。我很高兴被证明是错误的,这确实是根本问题,因为我在XAML和它的陷阱方面没有任何经验。

如果需要更多的代码,我很乐意提供更多的片段。

hsgswve4

hsgswve41#

正如@jdweng所提出的,这个问题的根源是交叉线程。
我们最终将整个类创建 Package 在Microsoft 365的单独线程中。Exchange、FileSystem和FTP都是同步的,而Microsoft 365是异步的。

switch (source.Type)
            {
                case Model.SourceType.Exchange:
                    var sourceExchange = new Model.Exchange(source);
                    result = sourceExchange.IsAvailable(out errorMessage);
                    break;
                case Model.SourceType.FileSystem:
                    var sourceFilesystem = new Model.FileSystem(source);
                    result = sourceFilesystem.IsAvailable(out errorMessage);
                    break;
                case Model.SourceType.FTP:
                    var sourceFTP = new Model.FTP(source);
                    result = sourceFTP.IsAvailable(out errorMessage);
                    break;
                case Model.SourceType.Microsoft365:
                    string s = null;
                    var task = new Task<bool>(() =>
                    {
                        var microsoft365 = new Model.Microsoft365(source);
                        return microsoft365.IsAvailable(out s);
                    });
                    task.Start();
                    task.Wait();
                    result = task.Result;
                    errorMessage = s;

                    break;
            }

完全奇怪,这修复了它,但我不会再问问题,并会很高兴地采取这种变通办法。

相关问题