Skip to content

Commit 1a2a9f0

Browse files
fenggabgavrilMS
andauthored
Add mac broker console app support (#5274)
* Remove authority validation for broker flows, and adjust related tests * Add mac broker console app * Avoid authority validation only for macOS broker flow * Add new mac broker console app to LibsAndSamples.sln * Add util MacMainThreadScheduler, and switch to main thread before call into NativeInterop interactive API * Update src/client/Microsoft.Identity.Client/Utils/MacMainThreadScheduler.cs Co-authored-by: Bogdan Gavril <[email protected]> * Expose MacMainThreadScheduler to public, and use it in the sample app --------- Co-authored-by: Bogdan Gavril <[email protected]>
1 parent 7dc8cf4 commit 1a2a9f0

File tree

15 files changed

+605
-19
lines changed

15 files changed

+605
-19
lines changed

LibsAndSamples.sln

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ EndProject
186186
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Identity.Test.E2E.MSI", "tests\Microsoft.Identity.Test.E2e\Microsoft.Identity.Test.E2E.MSI.csproj", "{97995B86-AA0F-3AF9-DA40-85A6263E4391}"
187187
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MacMauiAppWithBroker", "tests\devapps\MacMauiAppWithBroker\MacMauiAppWithBroker.csproj", "{AEF6BB00-931F-4638-955D-24D735625C34}"
188188
EndProject
189+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MacConsoleAppWithBroker", "tests\devapps\MacConsoleAppWithBroker\MacConsoleAppWithBroker.csproj", "{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}"
190+
EndProject
189191
Global
190192
GlobalSection(SolutionConfigurationPlatforms) = preSolution
191193
Debug + MobileApps|Any CPU = Debug + MobileApps|Any CPU
@@ -1866,6 +1868,48 @@ Global
18661868
{AEF6BB00-931F-4638-955D-24D735625C34}.Release|x64.Build.0 = Release|Any CPU
18671869
{AEF6BB00-931F-4638-955D-24D735625C34}.Release|x86.ActiveCfg = Release|Any CPU
18681870
{AEF6BB00-931F-4638-955D-24D735625C34}.Release|x86.Build.0 = Release|Any CPU
1871+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|Any CPU.ActiveCfg = Debug|Any CPU
1872+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|Any CPU.Build.0 = Debug|Any CPU
1873+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|ARM.ActiveCfg = Debug|Any CPU
1874+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|ARM.Build.0 = Debug|Any CPU
1875+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|ARM64.ActiveCfg = Debug|Any CPU
1876+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|ARM64.Build.0 = Debug|Any CPU
1877+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|iPhone.ActiveCfg = Debug|Any CPU
1878+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|iPhone.Build.0 = Debug|Any CPU
1879+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|iPhoneSimulator.ActiveCfg = Debug|Any CPU
1880+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|iPhoneSimulator.Build.0 = Debug|Any CPU
1881+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|x64.ActiveCfg = Debug|Any CPU
1882+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|x64.Build.0 = Debug|Any CPU
1883+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|x86.ActiveCfg = Debug|Any CPU
1884+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug + MobileApps|x86.Build.0 = Debug|Any CPU
1885+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1886+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
1887+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|ARM.ActiveCfg = Debug|Any CPU
1888+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|ARM.Build.0 = Debug|Any CPU
1889+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
1890+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|ARM64.Build.0 = Debug|Any CPU
1891+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
1892+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|iPhone.Build.0 = Debug|Any CPU
1893+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
1894+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
1895+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|x64.ActiveCfg = Debug|Any CPU
1896+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|x64.Build.0 = Debug|Any CPU
1897+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|x86.ActiveCfg = Debug|Any CPU
1898+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Debug|x86.Build.0 = Debug|Any CPU
1899+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
1900+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|Any CPU.Build.0 = Release|Any CPU
1901+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|ARM.ActiveCfg = Release|Any CPU
1902+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|ARM.Build.0 = Release|Any CPU
1903+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|ARM64.ActiveCfg = Release|Any CPU
1904+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|ARM64.Build.0 = Release|Any CPU
1905+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|iPhone.ActiveCfg = Release|Any CPU
1906+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|iPhone.Build.0 = Release|Any CPU
1907+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
1908+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
1909+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x64.ActiveCfg = Release|Any CPU
1910+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x64.Build.0 = Release|Any CPU
1911+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x86.ActiveCfg = Release|Any CPU
1912+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0}.Release|x86.Build.0 = Release|Any CPU
18691913
EndGlobalSection
18701914
GlobalSection(SolutionProperties) = preSolution
18711915
HideSolutionNode = FALSE
@@ -1921,6 +1965,7 @@ Global
19211965
{DA9C3258-DEF6-7794-9762-20CF7B826839} = {BCAEE9AE-8D3E-4C77-A2E4-134E1552D5F8}
19221966
{97995B86-AA0F-3AF9-DA40-85A6263E4391} = {9B0B5396-4D95-4C15-82ED-DC22B5A3123F}
19231967
{AEF6BB00-931F-4638-955D-24D735625C34} = {34BE693E-3496-45A4-B1D2-D3A0E068EEDB}
1968+
{DBD18BC8-72E4-47D4-BD79-8DEBD9F2C0D0} = {34BE693E-3496-45A4-B1D2-D3A0E068EEDB}
19241969
EndGlobalSection
19251970
GlobalSection(ExtensibilityGlobals) = postSolution
19261971
SolutionGuid = {020399A9-DC27-4B82-9CAA-EF488665AC27}

src/client/Microsoft.Identity.Client.Broker/RuntimeBroker.cs

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,34 @@ public async Task<MsalTokenResponse> AcquireTokenInteractiveAsync(
186186
{
187187
if (readAccountResult.IsSuccess)
188188
{
189-
using (var result = await s_lazyCore.Value.AcquireTokenInteractivelyAsync(
190-
_parentHandle,
191-
authParams,
192-
authenticationRequestParameters.CorrelationId.ToString("D"),
193-
readAccountResult.Account,
194-
cancellationToken).ConfigureAwait(false))
189+
if (DesktopOsHelper.IsMac())
195190
{
191+
AuthResult result = null;
192+
await MacMainThreadScheduler.Instance().RunOnMainThreadAsync(async () =>
193+
{
194+
result = await s_lazyCore.Value.AcquireTokenInteractivelyAsync(
195+
_parentHandle,
196+
authParams,
197+
authenticationRequestParameters.CorrelationId.ToString("D"),
198+
readAccountResult.Account,
199+
cancellationToken).ConfigureAwait(false);
200+
}).ConfigureAwait(false);
196201
var errorMessage = "Could not acquire token interactively.";
197202
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
198203
}
204+
else // Non macOS
205+
{
206+
using (var result = await s_lazyCore.Value.AcquireTokenInteractivelyAsync(
207+
_parentHandle,
208+
authParams,
209+
authenticationRequestParameters.CorrelationId.ToString("D"),
210+
readAccountResult.Account,
211+
cancellationToken).ConfigureAwait(false))
212+
{
213+
var errorMessage = "Could not acquire token interactively.";
214+
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
215+
}
216+
}
199217
}
200218
else
201219
{
@@ -238,16 +256,34 @@ private async Task<MsalTokenResponse> SignInInteractivelyAsync(
238256
string loginHint = authenticationRequestParameters.LoginHint ?? authenticationRequestParameters?.Account?.Username;
239257
_logger?.Verbose(() => "[RuntimeBroker] AcquireTokenInteractive - login hint provided? " + !string.IsNullOrEmpty(loginHint));
240258

241-
using (var result = await s_lazyCore.Value.SignInInteractivelyAsync(
242-
_parentHandle,
243-
authParams,
244-
authenticationRequestParameters.CorrelationId.ToString("D"),
245-
loginHint,
246-
cancellationToken).ConfigureAwait(false))
259+
if (DesktopOsHelper.IsMac())
247260
{
261+
AuthResult result = null;
262+
await MacMainThreadScheduler.Instance().RunOnMainThreadAsync(async () =>
263+
{
264+
result = await s_lazyCore.Value.SignInInteractivelyAsync(
265+
_parentHandle,
266+
authParams,
267+
authenticationRequestParameters.CorrelationId.ToString("D"),
268+
loginHint,
269+
cancellationToken).ConfigureAwait(false);
270+
}).ConfigureAwait(false);
248271
var errorMessage = "Could not sign in interactively.";
249272
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
250273
}
274+
else // Non macOS
275+
{
276+
using (var result = await s_lazyCore.Value.SignInInteractivelyAsync(
277+
_parentHandle,
278+
authParams,
279+
authenticationRequestParameters.CorrelationId.ToString("D"),
280+
loginHint,
281+
cancellationToken).ConfigureAwait(true))
282+
{
283+
var errorMessage = "Could not sign in interactively.";
284+
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
285+
}
286+
}
251287
}
252288

253289
return msalTokenResponse;
@@ -268,14 +304,31 @@ private async Task<MsalTokenResponse> AcquireTokenInteractiveDefaultUserAsync(
268304
_brokerOptions,
269305
_logger))
270306
{
271-
using (NativeInterop.AuthResult result = await s_lazyCore.Value.SignInAsync(
307+
if (DesktopOsHelper.IsMac())
308+
{
309+
AuthResult result = null;
310+
await MacMainThreadScheduler.Instance().RunOnMainThreadAsync(async () =>
311+
{
312+
result = await s_lazyCore.Value.SignInAsync(
313+
_parentHandle,
314+
authParams,
315+
authenticationRequestParameters.CorrelationId.ToString("D"),
316+
cancellationToken).ConfigureAwait(false);
317+
}).ConfigureAwait(false);
318+
var errorMessage = "Could not sign in interactively with the default OS account.";
319+
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
320+
}
321+
else // Non macOS
322+
{
323+
using (NativeInterop.AuthResult result = await s_lazyCore.Value.SignInAsync(
272324
_parentHandle,
273325
authParams,
274326
authenticationRequestParameters.CorrelationId.ToString("D"),
275327
cancellationToken).ConfigureAwait(false))
276-
{
277-
var errorMessage = "Could not sign in interactively with the default OS account.";
278-
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
328+
{
329+
var errorMessage = "Could not sign in interactively with the default OS account.";
330+
msalTokenResponse = WamAdapters.HandleResponse(result, authenticationRequestParameters, _logger, errorMessage);
331+
}
279332
}
280333
}
281334

src/client/Microsoft.Identity.Client/Instance/AuthorityManager.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Identity.Client.Instance.Discovery;
77
using Microsoft.Identity.Client.Instance.Validation;
88
using Microsoft.Identity.Client.Internal;
9+
using Microsoft.Identity.Client.PlatformsCommon.Shared;
910
using Microsoft.Identity.Client.Utils;
1011
using static Microsoft.Identity.Client.AuthorityInfo;
1112

@@ -47,7 +48,15 @@ public async Task<InstanceDiscoveryMetadataEntry> GetInstanceDiscoveryEntryAsync
4748

4849
public async Task RunInstanceDiscoveryAndValidationAsync()
4950
{
50-
if (!_instanceDiscoveryAndValidationExecuted)
51+
if (DesktopOsHelper.IsMac() && _requestContext.ServiceBundle.Config.IsBrokerEnabled)
52+
{
53+
// On macOS, for broker flows we should avoid authority validation. Internally, we should avoid any network requests to prevent context switch.
54+
// Interactive calls need to happen in the main thread, making network calls will switch to another thread and not easy to go back.
55+
_metadata = _requestContext.ServiceBundle.InstanceDiscoveryManager.GetMetadataEntryAvoidNetwork(
56+
_initialAuthority.AuthorityInfo,
57+
_requestContext);
58+
}
59+
else if (!_instanceDiscoveryAndValidationExecuted)
5160
{
5261
// This will make a network call unless instance discovery is cached, but this OK
5362
// GetAccounts and AcquireTokenSilent do not need this

src/client/Microsoft.Identity.Client/Instance/Discovery/IInstanceDiscoveryManager.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ namespace Microsoft.Identity.Client.Instance.Discovery
1212
/// </summary>
1313
internal interface IInstanceDiscoveryManager
1414
{
15+
InstanceDiscoveryMetadataEntry GetMetadataEntryAvoidNetwork(
16+
AuthorityInfo authorityInfo,
17+
RequestContext requestContext);
1518
Task<InstanceDiscoveryMetadataEntry> GetMetadataEntryTryAvoidNetworkAsync(
1619
AuthorityInfo authorityinfo,
1720
IEnumerable<string> existingEnvironmentsInCache,

src/client/Microsoft.Identity.Client/Instance/Discovery/InstanceDiscoveryManager.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,25 @@ public InstanceDiscoveryManager(
8080
}
8181
}
8282

83+
public InstanceDiscoveryMetadataEntry GetMetadataEntryAvoidNetwork(
84+
AuthorityInfo authorityInfo,
85+
RequestContext requestContext)
86+
{
87+
string environment = authorityInfo.Host;
88+
InstanceDiscoveryMetadataEntry entry = null;
89+
if (requestContext.ServiceBundle.Config.IsInstanceDiscoveryEnabled)
90+
{
91+
entry = _networkCacheMetadataProvider.GetMetadata(environment, requestContext.Logger) ??
92+
_knownMetadataProvider.GetMetadata(environment, null, requestContext.Logger);
93+
}
94+
if (entry == null)
95+
{
96+
requestContext.Logger.Info(() => $"Skipping Instance discovery for {authorityInfo.AuthorityType} authority and use single authority.");
97+
entry = CreateEntryForSingleAuthority(authorityInfo.CanonicalAuthority);
98+
}
99+
return entry;
100+
}
101+
83102
public async Task<InstanceDiscoveryMetadataEntry> GetMetadataEntryTryAvoidNetworkAsync(
84103
AuthorityInfo authorityInfo,
85104
IEnumerable<string> existingEnvironmentsInCache,

src/client/Microsoft.Identity.Client/Internal/Requests/Interactive/InteractiveRequest.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
using Microsoft.Identity.Client.Instance;
1010
using Microsoft.Identity.Client.Internal.Broker;
1111
using Microsoft.Identity.Client.OAuth2;
12+
using Microsoft.Identity.Client.PlatformsCommon.Shared;
1213
using Microsoft.Identity.Client.UI;
14+
using Microsoft.Identity.Client.Utils;
1315

1416
namespace Microsoft.Identity.Client.Internal.Requests
1517
{
@@ -63,8 +65,45 @@ protected override async Task<AuthenticationResult> ExecuteAsync(
6365
{
6466
await ResolveAuthorityAsync().ConfigureAwait(false);
6567
cancellationToken.ThrowIfCancellationRequested();
66-
MsalTokenResponse tokenResponse = await GetTokenResponseAsync(cancellationToken)
67-
.ConfigureAwait(false);
68+
MsalTokenResponse tokenResponse = null;
69+
if (DesktopOsHelper.IsMac() && ServiceBundle.Config.IsBrokerEnabled)
70+
{
71+
var macMainThreadScheduler = MacMainThreadScheduler.Instance();
72+
if (!macMainThreadScheduler.IsCurrentlyOnMainThread())
73+
{
74+
throw new MsalClientException(
75+
MsalError.WamUiThread,
76+
"Interactive requests with mac broker enabled must be executed on the main thread on macOS.");
77+
}
78+
bool messageLoopStarted = macMainThreadScheduler.IsRunning();
79+
var tcs = new TaskCompletionSource<MsalTokenResponse>();
80+
_ = Task.Run(async () =>
81+
{
82+
try
83+
{
84+
MsalTokenResponse response = await GetTokenResponseAsync(cancellationToken).ConfigureAwait(false);
85+
tcs.SetResult(response);
86+
}
87+
catch (Exception ex)
88+
{
89+
_logger.Error($"Error in background GetTokenResponseAsync: {ex}");
90+
tcs.SetException(ex);
91+
}
92+
finally
93+
{
94+
if (!messageLoopStarted)
95+
macMainThreadScheduler.Stop();
96+
}
97+
});
98+
if (!messageLoopStarted)
99+
macMainThreadScheduler.StartMessageLoop();
100+
tokenResponse = await tcs.Task.ConfigureAwait(false);
101+
}
102+
else
103+
{
104+
tokenResponse = await GetTokenResponseAsync(cancellationToken)
105+
.ConfigureAwait(false);
106+
}
68107
return await CacheTokenResponseAndCreateAuthenticationResultAsync(tokenResponse)
69108
.ConfigureAwait(false);
70109
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler
2+
static Microsoft.Identity.Client.Utils.MacMainThreadScheduler.Instance() -> Microsoft.Identity.Client.Utils.MacMainThreadScheduler
3+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.IsCurrentlyOnMainThread() -> bool
4+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.IsRunning() -> bool
5+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.Stop() -> void
6+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.RunOnMainThreadAsync(System.Func<System.Threading.Tasks.Task> asyncAction) -> System.Threading.Tasks.Task
7+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.StartMessageLoop() -> void
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler
2+
static Microsoft.Identity.Client.Utils.MacMainThreadScheduler.Instance() -> Microsoft.Identity.Client.Utils.MacMainThreadScheduler
3+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.IsCurrentlyOnMainThread() -> bool
4+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.IsRunning() -> bool
5+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.Stop() -> void
6+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.RunOnMainThreadAsync(System.Func<System.Threading.Tasks.Task> asyncAction) -> System.Threading.Tasks.Task
7+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.StartMessageLoop() -> void
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler
2+
static Microsoft.Identity.Client.Utils.MacMainThreadScheduler.Instance() -> Microsoft.Identity.Client.Utils.MacMainThreadScheduler
3+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.IsCurrentlyOnMainThread() -> bool
4+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.IsRunning() -> bool
5+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.Stop() -> void
6+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.RunOnMainThreadAsync(System.Func<System.Threading.Tasks.Task> asyncAction) -> System.Threading.Tasks.Task
7+
Microsoft.Identity.Client.Utils.MacMainThreadScheduler.StartMessageLoop() -> void

0 commit comments

Comments
 (0)