Skip to content

Commit faa4998

Browse files
authored
Use IList to avoid enumerator allocation (#3204)
* Use IList to avoid enumerator allocation * Cline addressing PR feedback * revert whitespace change
1 parent 48cdc0c commit faa4998

File tree

4 files changed

+88
-3
lines changed

4 files changed

+88
-3
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using BenchmarkDotNet.Attributes;
5+
using Microsoft.IdentityModel.Tokens;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
9+
namespace Microsoft.IdentityModel.Benchmarks
10+
{
11+
/// <summary>
12+
/// Benchmarks for validator methods to measure performance of different implementations
13+
/// </summary>
14+
public class ValidatorBenchmarks
15+
{
16+
private List<string> _audiences;
17+
private TokenValidationParameters _parametersWithList;
18+
private TokenValidationParameters _parametersWithEnumerable;
19+
20+
[GlobalSetup]
21+
public void Setup()
22+
{
23+
_audiences = ["audience1"];
24+
var validAudiences = new List<string> { "invalid1", "invalid2", "audience1" }; // Make sure audience is last to maximize iteration
25+
26+
_parametersWithList = new TokenValidationParameters
27+
{
28+
ValidAudiences = validAudiences
29+
};
30+
31+
_parametersWithEnumerable = new TokenValidationParameters
32+
{
33+
ValidAudiences = validAudiences.Select(x => x) // Force enumerable by using LINQ
34+
};
35+
}
36+
37+
[Benchmark(Baseline = true)]
38+
public void ValidateAudience_WithList()
39+
{
40+
Validators.ValidateAudience(_audiences, null, _parametersWithList);
41+
}
42+
43+
[Benchmark]
44+
public void ValidateAudience_WithEnumerable()
45+
{
46+
Validators.ValidateAudience(_audiences, null, _parametersWithEnumerable);
47+
}
48+
}
49+
}

src/Microsoft.IdentityModel.Tokens/Validators.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,10 @@ private static bool AudienceIsValid(IEnumerable<string> audiences, TokenValidati
143143
if (string.IsNullOrWhiteSpace(tokenAudience))
144144
continue;
145145

146-
foreach (string validAudience in validationParametersAudiences)
146+
bool TryMatchAudience(string validAudience)
147147
{
148148
if (string.IsNullOrWhiteSpace(validAudience))
149-
continue;
149+
return false;
150150

151151
if (AudiencesMatch(validationParameters, tokenAudience, validAudience))
152152
{
@@ -155,6 +155,25 @@ private static bool AudienceIsValid(IEnumerable<string> audiences, TokenValidati
155155

156156
return true;
157157
}
158+
159+
return false;
160+
}
161+
162+
if (validationParametersAudiences is IList<string> audienceList)
163+
{
164+
for (int i = 0; i < audienceList.Count; i++)
165+
{
166+
if (TryMatchAudience(audienceList[i]))
167+
return true;
168+
}
169+
}
170+
else
171+
{
172+
foreach (string validAudience in validationParametersAudiences)
173+
{
174+
if (TryMatchAudience(validAudience))
175+
return true;
176+
}
158177
}
159178
}
160179

test/Microsoft.IdentityModel.Tokens.Tests/Microsoft.IdentityModel.Tokens.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<ItemGroup>
2323
<PackageReference Include="Microsoft.Azure.KeyVault.Cryptography" Version="$(MicrosoftAzureKeyVaultCryptographyVersion)" />
2424
<PackageReference Include="System.Text.RegularExpressions" Version="$(SystemTextRegularExpressions)"/>
25-
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="$(MicrosoftRestClientRuntimeVersion)"/>
25+
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="$(MicrosoftRestClientRuntimeVersion)" />
2626
</ItemGroup>
2727

2828
<ItemGroup>

test/Microsoft.IdentityModel.Tokens.Tests/Validation/ValidatorsTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,23 @@ public static TheoryData<AudienceValidationTheoryData> ValidateAudienceTheoryDat
270270
Audiences = audiences1WithTwoSlashes,
271271
ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"),
272272
TokenValidationParameters = new TokenValidationParameters{ ValidAudience = audience1 }
273+
},
274+
new AudienceValidationTheoryData("ValidAudiencesList_OptimizedPath")
275+
{
276+
Audiences = new List<string> { "audience1" },
277+
TokenValidationParameters = new TokenValidationParameters
278+
{
279+
ValidAudiences = new List<string> { "invalidAudience", "audience1" } // Using List<string> to test IList optimization
280+
}
281+
},
282+
new AudienceValidationTheoryData("ValidAudiencesList_EmptyList_OptimizedPath")
283+
{
284+
Audiences = new List<string> { "audience1" },
285+
ExpectedException = ExpectedException.SecurityTokenInvalidAudienceException("IDX10214:"),
286+
TokenValidationParameters = new TokenValidationParameters
287+
{
288+
ValidAudiences = new List<string>() // Empty list should still return false through optimized path
289+
}
273290
}
274291
};
275292
}

0 commit comments

Comments
 (0)