Skip to content

Commit 10678db

Browse files
Avery-DunnbgavrilMS
authored andcommitted
Improve alias caching
1 parent bde9dc8 commit 10678db

5 files changed

Lines changed: 72 additions & 5 deletions

File tree

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ namespace Microsoft.Identity.Client.Instance.Discovery
88
internal interface INetworkCacheMetadataProvider
99
{
1010
void AddMetadata(string environment, InstanceDiscoveryMetadataEntry entry);
11+
12+
/// <summary>
13+
/// Caches <paramref name="entry"/> under each host in <paramref name="entry"/>.Aliases.
14+
/// If the entry has no aliases, falls back to <paramref name="fallbackEnvironment"/>.
15+
/// </summary>
16+
void AddMetadataWithAliases(InstanceDiscoveryMetadataEntry entry, string fallbackEnvironment);
17+
1118
InstanceDiscoveryMetadataEntry GetMetadata(string environment, ILoggerAdapter logger);
1219
}
1320
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ private async Task<InstanceDiscoveryMetadataEntry> FetchNetworkMetadataOrFallbac
212212
_knownMetadataProvider.GetMetadata(authorityUri.Host, Enumerable.Empty<string>(), requestContext.Logger)
213213
?? CreateEntryForSingleAuthority(authorityUri);
214214

215-
_networkCacheMetadataProvider.AddMetadata(authorityUri.Host, fallbackEntry);
215+
_networkCacheMetadataProvider.AddMetadataWithAliases(fallbackEntry, authorityUri.Host);
216216

217217
return fallbackEntry;
218218
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ public void AddMetadata(string environment, InstanceDiscoveryMetadataEntry entry
2626
s_cache.AddOrUpdate(environment, entry, (_, _) => entry);
2727
}
2828

29+
public void AddMetadataWithAliases(InstanceDiscoveryMetadataEntry entry, string fallbackEnvironment)
30+
{
31+
string[] aliases = entry?.Aliases;
32+
if (aliases != null && aliases.Length > 0)
33+
{
34+
foreach (string alias in aliases)
35+
{
36+
if (!string.IsNullOrWhiteSpace(alias))
37+
s_cache.AddOrUpdate(alias, entry, (_, _) => entry);
38+
}
39+
}
40+
else if (!string.IsNullOrWhiteSpace(fallbackEnvironment))
41+
{
42+
s_cache.AddOrUpdate(fallbackEnvironment, entry, (_, _) => entry);
43+
}
44+
}
45+
2946
internal static void ResetStaticCacheForTest()
3047
{
3148
s_cache.Clear();

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,7 @@ private void CacheInstanceDiscoveryMetadata(InstanceDiscoveryResponse instanceDi
6767
{
6868
foreach (InstanceDiscoveryMetadataEntry entry in instanceDiscoveryResponse.Metadata ?? Enumerable.Empty<InstanceDiscoveryMetadataEntry>())
6969
{
70-
foreach (string aliasedEnvironment in entry.Aliases ?? Enumerable.Empty<string>())
71-
{
72-
_networkCacheMetadataProvider.AddMetadata(aliasedEnvironment, entry);
73-
}
70+
_networkCacheMetadataProvider.AddMetadataWithAliases(entry, fallbackEnvironment: null);
7471
}
7572
}
7673

tests/Microsoft.Identity.Test.Unit/CoreTests/InstanceTests/InstanceDiscoveryManagerTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,52 @@ public async Task NetworkProviderFailures_AreIgnored_Async()
251251
_knownMetadataProvider.Received(1).GetMetadata("some_env.com", Enumerable.Empty<string>(), Arg.Any<ILoggerAdapter>());
252252
}
253253

254+
[TestMethod]
255+
public async Task NetworkProviderFailures_FallbackEntry_AllAliasesCached_Async()
256+
{
257+
// Arrange — use a real cache so we can inspect what was written
258+
var realNetworkCache = new NetworkCacheMetadataProvider();
259+
260+
var multiAliasEntry = new InstanceDiscoveryMetadataEntry()
261+
{
262+
Aliases = new[] { "some_env.com", "alias1.some_env.com", "alias2.some_env.com" },
263+
PreferredCache = "some_env.com",
264+
PreferredNetwork = "some_env.com"
265+
};
266+
267+
_knownMetadataProvider
268+
.GetMetadata("some_env.com", Enumerable.Empty<string>(), Arg.Any<ILoggerAdapter>())
269+
.Returns(multiAliasEntry);
270+
271+
_networkMetadataProvider
272+
.When(x => x.GetMetadataAsync(Arg.Any<Uri>(), _testRequestContext))
273+
.Do(_ => throw new MsalServiceException("endpoint_busy", "simulated failure"));
274+
275+
_discoveryManager = new InstanceDiscoveryManager(
276+
_harness.HttpManager,
277+
null,
278+
null,
279+
_knownMetadataProvider,
280+
realNetworkCache,
281+
_networkMetadataProvider);
282+
283+
// Act
284+
var result = await _discoveryManager.GetMetadataEntryAsync(
285+
AuthorityInfo.FromAuthorityUri("https://some_env.com/tid", true),
286+
_testRequestContext)
287+
.ConfigureAwait(false);
288+
289+
Assert.AreSame(multiAliasEntry, result);
290+
291+
// Assert — fallback entry must be cached under every alias so subsequent requests
292+
// using any alias won't retry the failing network call
293+
ILoggerAdapter logger = _testRequestContext.Logger;
294+
Assert.IsNotNull(realNetworkCache.GetMetadata("some_env.com", logger), "Primary host should be cached");
295+
Assert.IsNotNull(realNetworkCache.GetMetadata("alias1.some_env.com", logger), "First alias should be cached");
296+
Assert.IsNotNull(realNetworkCache.GetMetadata("alias2.some_env.com", logger), "Second alias should be cached");
297+
Assert.IsNull(realNetworkCache.GetMetadata("unrelated_env.com", logger), "Unrelated host should not be in cache");
298+
}
299+
254300
[TestMethod]
255301
public async Task NetworkProviderFailures_WithNoKnownMetadata_ContinuesWithAuthority_Async()
256302
{

0 commit comments

Comments
 (0)