Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
62f2a61
Initial plan
Copilot Sep 17, 2026
d37edba
test(csharp): cover deterministic Response-to-Result model names
Copilot Sep 18, 2026
4af1e99
feat(csharp): normalize Response model suffixes to Result
Copilot Sep 18, 2026
d9ed5f8
fix(csharp): account for Result-targeted customization aliases
Copilot Sep 18, 2026
8c8f5d2
refactor(csharp): scope response name fallbacks to ModelProvider
Copilot Sep 18, 2026
dbba17b
refactor(csharp): keep response suffix normalization in ModelProvider
Copilot Sep 18, 2026
2500c9a
refactor(csharp): reduce naming collision lookups and cover compatibi…
Copilot Sep 18, 2026
9d543b6
refactor(csharp): consolidate response naming lookup helpers
Copilot Sep 18, 2026
6584968
fix(csharp): honor customized result model names
Copilot Sep 18, 2026
14a3556
perf(csharp): cache model naming lookups
Copilot Sep 21, 2026
5cddfae
refactor(csharp): type model name cache entries
Copilot Sep 21, 2026
6200dd5
refactor(csharp): make naming cache initialization lazy
Copilot Sep 21, 2026
b84a319
refactor(csharp): clarify naming cache invariants
Copilot Sep 21, 2026
6287c0c
refactor(csharp): freeze naming cache entries
Copilot Sep 21, 2026
fd3e2b6
refactor(csharp): simplify cached alias state
Copilot Sep 21, 2026
c3558a0
refactor(csharp): bind name cache to generator
Copilot Sep 21, 2026
f7dc006
refactor(csharp): avoid copying name cache entries
Copilot Sep 21, 2026
8df38f8
fix(csharp): simplify deterministic result collisions
Copilot Sep 21, 2026
0c7dd43
fix(csharp): preserve shipped result name ownership
Copilot Sep 21, 2026
052c3f7
refactor(csharp): clarify result ownership rules
Copilot Sep 21, 2026
75d51a0
refactor(csharp): centralize customization lookup guard
Copilot Sep 21, 2026
72192c8
refactor(csharp): unify model naming helpers
Copilot Sep 21, 2026
c109740
refactor(csharp): clarify model name conflicts
Copilot Sep 21, 2026
7a1ef84
fix(csharp): reserve standalone result customizations
Copilot Sep 21, 2026
adaf048
refactor(csharp): inline customization reservation
Copilot Sep 21, 2026
152c949
fix(csharp): isolate customized client model names
Copilot Sep 21, 2026
9cd342a
refactor(csharp): unify customization collision checks
Copilot Sep 21, 2026
da5c60c
refactor(csharp): simplify model collision checks
Copilot Sep 21, 2026
f4511d0
fix(csharp): cover hidden model name collisions
Copilot Sep 21, 2026
30f7b3f
fix(csharp): prevent physical model name collisions
Copilot Sep 21, 2026
4eafe26
fix(csharp): match emitted model/enum criteria in Result collision scan
Copilot Sep 21, 2026
d4cd999
refactor(csharp): cache emitted naming inventory
Copilot Sep 21, 2026
1402733
refactor(csharp): share emitted type collision cache
Copilot Sep 21, 2026
05c7fd4
docs(csharp): clarify emitted collision cache rules
Copilot Sep 21, 2026
11ec3fb
refactor(csharp): preserve customization enum scan
Copilot Sep 21, 2026
30761ce
refactor(csharp): clarify emitted model predicate
Copilot Sep 21, 2026
7bb4ae4
refactor(csharp): guard emitted type cache
Copilot Sep 21, 2026
b68d020
test(csharp): cover repeated emitted enum checks
Copilot Sep 21, 2026
d296398
refactor(csharp): simplify unknown variant cache scan
Copilot Sep 21, 2026
1d1fb59
refactor(csharp): key emitted cache by generator
Copilot Sep 21, 2026
3b8a98e
refactor(csharp): avoid retaining generator cache keys
Copilot Sep 21, 2026
a04613e
fix(csharp): reserve resolved external result names
Copilot Sep 22, 2026
7188912
fix(csharp): ignore non-emitted enum customizations
Copilot Sep 22, 2026
5b677bf
refactor(csharp): simplify model name collision checks
Copilot Sep 22, 2026
3785df9
refactor(csharp): avoid unnecessary name normalization
Copilot Sep 22, 2026
97911d4
test(csharp): clarify external collision coverage
Copilot Sep 22, 2026
ea76334
test(csharp): name external collision scenario
Copilot Sep 22, 2026
eaa3cd0
test(csharp): clarify external model collision cases
Copilot Sep 22, 2026
e1f18d3
test(csharp): distinguish external model collision cases
Copilot Sep 22, 2026
e9fa9f7
test(csharp): clarify external metadata behavior
Copilot Sep 22, 2026
798cdee
test(csharp): name unresolvable external coverage
Copilot Sep 22, 2026
df7b9f3
test(csharp): clarify unresolvable CLR scenario
Copilot Sep 22, 2026
78ff950
refactor(csharp): simplify emitted type caches
Copilot Sep 22, 2026
6b997fd
refactor(csharp): restore external type encapsulation
Copilot Sep 22, 2026
7fc54e2
refactor(csharp): inline emitted type caches
Copilot Sep 22, 2026
261fd77
refactor(csharp): consolidate emitted type inventory
Copilot Sep 22, 2026
3ff3b37
fix(csharp): break Result ownership ties deterministically
Copilot Sep 22, 2026
fa1f044
refactor(csharp): move emitted type filtering to InputLibrary
Copilot Sep 22, 2026
baed7a8
refactor(csharp): internalize non-external type inventories
Copilot Sep 22, 2026
24c8f9d
refactor(csharp): remove duplicate response ownership
Copilot Sep 22, 2026
f9eb719
refactor(csharp): remove response collision detection
Copilot Sep 22, 2026
ebd8622
refactor(csharp): thread namespace through name normalization
Copilot Sep 23, 2026
3aa8521
fix(csharp): scope CodeGenType aliases to their owning input type
Copilot Sep 23, 2026
7623f29
docs(csharp): explain client-only customization ownership scope
Copilot Sep 23, 2026
2b77efb
revert(csharp): restore BuildNamespace use in NormalizeTypeName
Copilot Sep 23, 2026
72e21bb
refactor(csharp): simplify client customization lookup
Copilot Sep 23, 2026
6fdba6f
refactor(csharp): remove client customization guard
Copilot Sep 23, 2026
257f96d
revert(csharp): restore SourceInputModel lookup
Copilot Sep 23, 2026
d3e6088
Merge branch 'main' into copilot/support-deterministic-naming
jorgerangel-msft Sep 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ await GenerateAndAssertFiles(
clients: [client],
customFiles: [],
expectedFiles: [],
publicModelNames: ["MetadataOnlyResponse"]);
publicModelNames: ["MetadataOnlyResult"]);
}

[Test]
Expand Down Expand Up @@ -227,13 +227,13 @@ await GenerateAndAssertFiles(
clients: [client],
customFiles: [],
expectedFiles: [
Path.Combine("src", "Generated", "Models", "MetadataOnlyResponse.cs"),
Path.Combine("src", "Generated", "Models", "MetadataOnlyResponse.Serialization.cs")
Path.Combine("src", "Generated", "Models", "MetadataOnlyResult.cs"),
Path.Combine("src", "Generated", "Models", "MetadataOnlyResult.Serialization.cs")
],
internalModelNames: ["MetadataOnlyResponse"],
internalModelNames: ["MetadataOnlyResult"],
configureGenerator: () =>
{
var provider = CodeModelGenerator.Instance.OutputLibrary.TypeProviders.Single(provider => provider.Name == "MetadataOnlyResponse");
var provider = CodeModelGenerator.Instance.OutputLibrary.TypeProviders.Single(provider => provider.Name == "MetadataOnlyResult");
CodeModelGenerator.Instance.AddTypeToKeep(provider);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace Microsoft.TypeSpec.Generator.Providers
public class ModelProvider : TypeProvider
{
private const string AdditionalBinaryDataPropsFieldDescription = "Keeps track of any properties unknown to the library.";
private const string ResponseSuffix = "Response";
private readonly InputModelType _inputModel;
// Note the description cannot be built from the constructor as it would lead to a circular dependency between the base
// and derived models resulting in a stack overflow.
Expand Down Expand Up @@ -317,6 +318,70 @@ protected override string BuildName()
return NormalizeTypeNameForNewContract(_inputModel.Name.ToIdentifierName());
}

private protected override string NormalizeTypeName(string name)
{
var normalizedName = base.NormalizeTypeName(name);
if (!normalizedName.EndsWith(ResponseSuffix, StringComparison.Ordinal))
{
return normalizedName;
}

var typeNamespace = BuildNamespace();
var sourceInputModel = CodeModelGenerator.Instance.SourceInputModel;
if (sourceInputModel.FindForTypeInCurrentCompilation(typeNamespace, normalizedName, DeclaringTypeName) is not null ||
sourceInputModel.FindForTypeInLastContract(typeNamespace, normalizedName, DeclaringTypeName) is not null)
{
return normalizedName;
}

return $"{normalizedName[..^ResponseSuffix.Length]}Result";
Comment thread
jorgerangel-msft marked this conversation as resolved.
}

private protected override TypeProvider? BuildCustomCodeView(string? generatedTypeName = null, string? generatedTypeNamespace = null)
{
var typeNamespace = generatedTypeNamespace ?? BuildNamespace();
var typeName = generatedTypeName ?? BuildName();
var customCodeView = base.BuildCustomCodeView(typeName, typeNamespace);
return customCodeView ?? BuildResponseSuffixFallbackView(
typeName,
typeNamespace,
(name, ns) => base.BuildCustomCodeView(name, ns));
}

private protected override TypeProvider? BuildLastContractView(string? generatedTypeName = null, string? generatedTypeNamespace = null)
{
var typeNamespace = generatedTypeNamespace ?? CustomCodeView?.Type.Namespace ?? BuildNamespace();
var typeName = generatedTypeName ?? CustomCodeView?.Name ?? BuildName();
var lastContractView = base.BuildLastContractView(typeName, typeNamespace);
return lastContractView ?? BuildResponseSuffixFallbackView(
typeName,
typeNamespace,
(name, ns) => base.BuildLastContractView(name, ns));
}

private TypeProvider? BuildResponseSuffixFallbackView(
string typeName,
string typeNamespace,
Func<string, string, TypeProvider?> buildView)
{
if (_inputModel.IsExactName)
{
return null;
}

var originalName = _inputModel.Name.ToIdentifierName();
var normalizedOriginalName = originalName.NormalizeCSharpAcronyms();
if (!normalizedOriginalName.EndsWith(ResponseSuffix, StringComparison.Ordinal) ||
originalName == typeName ||
typeName != $"{normalizedOriginalName[..^ResponseSuffix.Length]}Result")
{
return null;
}

return buildView(originalName, typeNamespace) ??
(normalizedOriginalName == originalName ? null : buildView(normalizedOriginalName, typeNamespace));
}

protected override TypeSignatureModifiers BuildDeclarationModifiers()
{
var customCodeModifiers = CustomCodeView?.DeclarationModifiers ?? TypeSignatureModifiers.None;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public abstract class TypeProvider
private Lazy<CanonicalTypeProvider> _canonicalView;
private Lazy<TypeProvider> _specView;
private Lazy<string?> _declaringTypeName;
private protected string? DeclaringTypeName => _declaringTypeName.Value;
private readonly InputType? _inputType;
private readonly Dictionary<string, PropertyProvider> _generatedPropertiesBySpecName = new(StringComparer.Ordinal);

Expand Down Expand Up @@ -748,7 +749,7 @@ protected string NormalizeTypeNameForNewContract(string name)
return name;
}

var normalizedName = name.NormalizeCSharpAcronyms();
var normalizedName = NormalizeTypeName(name);
if (normalizedName == name)
{
return name;
Expand All @@ -761,6 +762,8 @@ protected string NormalizeTypeNameForNewContract(string name)
return lastContractType is null ? normalizedName : name;
}

private protected virtual string NormalizeTypeName(string name) => name.NormalizeCSharpAcronyms();

/// <summary>
/// Resets only the cached methods so they are rebuilt on next access.
/// Use this instead of <see cref="Reset"/> when you need to force a method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public void BuildEnumType_ValidateStringBasedFixedEnum()
[TestCase(false, "IPV4AddressIPV6", false, "IPV4AddressIPV6")]
[TestCase(true, "OsloIpsumOsmosisDbz", false, "OsloIpsumOsmosisDbz")]
[TestCase(false, "IpKind", true, "IpKind")]
[TestCase(false, "WidgetResponse", false, "WidgetResponse")]
Comment thread
jorgerangel-msft marked this conversation as resolved.
[TestCase(true, "IpResponse", false, "IPResponse")]
public void BuildEnumType_NormalizesTypeAcronymCasing(
bool isExtensible,
string inputName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,80 @@ public void TestBuildName_NormalizesAcronymCasing(string inputName, bool isExact
Assert.AreEqual(expectedName, modelProvider.Name);
}

[TestCase("WidgetResponse", false, "WidgetResult")]
[TestCase("Response", false, "Result")]
[TestCase("widget_response", false, "WidgetResult")]
[TestCase("IpResponse", false, "IPResult")]
[TestCase("WidgetResponseResponse", false, "WidgetResponseResult")]
[TestCase("WidgetResponse", true, "WidgetResponse")]
[TestCase("IpResponse", true, "IpResponse")]
[TestCase("WidgetResult", false, "WidgetResult")]
[TestCase("ResponseWidget", false, "ResponseWidget")]
[TestCase("WidgetResponses", false, "WidgetResponses")]
[TestCase("Widgetresponse", false, "Widgetresponse")]
public void TestBuildName_ResponseSuffix(string inputName, bool isExactName, string expectedName)
{
var inputModel = InputFactory.Model(
inputName,
isExactName: isExactName,
properties: [InputFactory.Property("serviceResponse", InputPrimitiveType.String)]);
var model = new ModelProvider(inputModel);

Assert.AreEqual(expectedName, model.Name);
Assert.AreEqual($"{expectedName}.cs", Path.GetFileName(model.RelativeFilePath));
Assert.AreEqual("ServiceResponse", model.Properties[0].Name);
}

[TestCase("WidgetResponse", "WidgetResponse", false, false)]
[TestCase("WidgetResponse", "WidgetResponse", true, false)]
[TestCase("WidgetResponse", "WidgetResponse", false, true)]
[TestCase("WidgetResponse", "WidgetResponse", true, true)]
[TestCase("IpResponse", "IPResponse", false, false)]
[TestCase("IpResponse", "IPResponse", true, false)]
[TestCase("IpResponse", "IPResponse", false, true)]
[TestCase("IpResponse", "IPResponse", true, true)]
[TestCase("DbResponse", "DbResponse", false, false)]
[TestCase("DbResponse", "DbResponse", true, false)]
[TestCase("DbResponse", "DbResponse", false, true)]
[TestCase("DbResponse", "DbResponse", true, true)]
public async Task TestBuildName_ResponseSuffixPreservesExistingName(
string inputName, string expectedName, bool lastContract, bool updateNamespace)
{
var inputModel = InputFactory.Model(
inputName, @namespace: updateNamespace ? "Sample" : "Sample.Models");
var compilation = await Helpers.GetCompilationFromDirectoryAsync();
await MockHelpers.LoadMockGeneratorAsync(
inputModelTypes: [inputModel],
compilation: lastContract ? null : () => Task.FromResult(compilation),
lastContractCompilation: lastContract ? () => Task.FromResult(compilation) : null);
var model = CodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel)!;

if (updateNamespace)
{
Assert.That(model.Name, Does.EndWith("Result"));
model.Update(@namespace: "Sample.Models");
}

Assert.AreEqual(expectedName, model.Name);
Assert.IsNotNull(lastContract ? model.LastContractView : model.CustomCodeView);
}

[TestCase("WidgetResponse", "CustomizedWidget")]
[TestCase("IpResponse", "CustomizedIP")]
[TestCase("GadgetResponse", "CustomizedGadget")]
public async Task TestBuildName_ResponseSuffixPreservesCustomName(string inputName, string expectedName)
{
var inputModel = InputFactory.Model(inputName);
await MockHelpers.LoadMockGeneratorAsync(
inputModelTypes: [inputModel],
compilation: async () => await Helpers.GetCompilationFromDirectoryAsync());

var model = CodeModelGenerator.Instance.TypeFactory.CreateModel(inputModel)!;

Assert.AreEqual(expectedName, model.Name);
Assert.IsNotNull(model.CustomCodeView);
}

[Test]
public async Task TestBuildName_BackCompatTakesPrecedenceOverAcronymNormalization()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.TypeSpec.Generator.Customizations;

namespace Sample.Models
{
[CodeGenType("WidgetResponse")]
public partial class CustomizedWidget
{
}

[CodeGenType("IPResponse")]
public partial class CustomizedIP
{
}

[CodeGenType("GadgetResult")]
public partial class CustomizedGadget
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Sample.Models
{
public partial class WidgetResponse
{
}

public partial class IPResponse
{
}

public partial class DbResponse
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
ClientResult result = await GetNextResponseAsync(message).ConfigureAwait(false);
yield return result;

nextToken = ((ListWithContinuationTokenResponse)result).NextToken;
nextToken = ((ListWithContinuationTokenResult)result).NextToken;
if (string.IsNullOrEmpty(nextToken))
{
yield break;
Expand All @@ -55,7 +55,7 @@ public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
/// <returns> The continuation token for the specified page. </returns>
public override ContinuationToken GetContinuationToken(ClientResult page)
{
string nextPage = ((ListWithContinuationTokenResponse)page).NextToken;
string nextPage = ((ListWithContinuationTokenResult)page).NextToken;
if (!string.IsNullOrEmpty(nextPage))
{
return ContinuationToken.FromBytes(BinaryData.FromString(nextPage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
ClientResult result = await GetNextResponseAsync(message).ConfigureAwait(false);
yield return result;

nextToken = ((ListWithContinuationTokenResponse)result).NextToken;
nextToken = ((ListWithContinuationTokenResult)result).NextToken;
if (string.IsNullOrEmpty(nextToken))
{
yield break;
Expand All @@ -55,7 +55,7 @@ public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
/// <returns> The continuation token for the specified page. </returns>
public override ContinuationToken GetContinuationToken(ClientResult page)
{
string nextPage = ((ListWithContinuationTokenResponse)page).NextToken;
string nextPage = ((ListWithContinuationTokenResult)page).NextToken;
if (!string.IsNullOrEmpty(nextPage))
{
return ContinuationToken.FromBytes(BinaryData.FromString(nextPage));
Expand All @@ -71,7 +71,7 @@ public override ContinuationToken GetContinuationToken(ClientResult page)
/// <returns> The values from the specified page. </returns>
protected override async IAsyncEnumerable<Thing> GetValuesFromPageAsync(ClientResult page)
{
foreach (Thing item in ((ListWithContinuationTokenResponse)page).Things)
foreach (Thing item in ((ListWithContinuationTokenResult)page).Things)
{
yield return item;
await Task.Yield();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override IEnumerable<ClientResult> GetRawPages()
ClientResult result = GetNextResponse(message);
yield return result;

nextToken = ((ListWithContinuationTokenResponse)result).NextToken;
nextToken = ((ListWithContinuationTokenResult)result).NextToken;
if (string.IsNullOrEmpty(nextToken))
{
yield break;
Expand All @@ -54,7 +54,7 @@ public override IEnumerable<ClientResult> GetRawPages()
/// <returns> The continuation token for the specified page. </returns>
public override ContinuationToken GetContinuationToken(ClientResult page)
{
string nextPage = ((ListWithContinuationTokenResponse)page).NextToken;
string nextPage = ((ListWithContinuationTokenResult)page).NextToken;
if (!string.IsNullOrEmpty(nextPage))
{
return ContinuationToken.FromBytes(BinaryData.FromString(nextPage));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override IEnumerable<ClientResult> GetRawPages()
ClientResult result = GetNextResponse(message);
yield return result;

nextToken = ((ListWithContinuationTokenResponse)result).NextToken;
nextToken = ((ListWithContinuationTokenResult)result).NextToken;
if (string.IsNullOrEmpty(nextToken))
{
yield break;
Expand All @@ -54,7 +54,7 @@ public override IEnumerable<ClientResult> GetRawPages()
/// <returns> The continuation token for the specified page. </returns>
public override ContinuationToken GetContinuationToken(ClientResult page)
{
string nextPage = ((ListWithContinuationTokenResponse)page).NextToken;
string nextPage = ((ListWithContinuationTokenResult)page).NextToken;
if (!string.IsNullOrEmpty(nextPage))
{
return ContinuationToken.FromBytes(BinaryData.FromString(nextPage));
Expand All @@ -70,7 +70,7 @@ public override ContinuationToken GetContinuationToken(ClientResult page)
/// <returns> The values from the specified page. </returns>
protected override IEnumerable<Thing> GetValuesFromPage(ClientResult page)
{
return ((ListWithContinuationTokenResponse)page).Things;
return ((ListWithContinuationTokenResult)page).Things;
}

/// <summary> Sends the request in the pipeline message and returns the response. </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public override ContinuationToken GetContinuationToken(ClientResult page)
/// <returns> The values from the specified page. </returns>
protected override async IAsyncEnumerable<Thing> GetValuesFromPageAsync(ClientResult page)
{
foreach (Thing item in ((ListWithContinuationTokenHeaderResponseResponse)page).Things)
foreach (Thing item in ((ListWithContinuationTokenHeaderResponseResult)page).Things)
{
yield return item;
await Task.Yield();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public override ContinuationToken GetContinuationToken(ClientResult page)
/// <returns> The values from the specified page. </returns>
protected override IEnumerable<Thing> GetValuesFromPage(ClientResult page)
{
return ((ListWithContinuationTokenHeaderResponseResponse)page).Things;
return ((ListWithContinuationTokenHeaderResponseResult)page).Things;
}

/// <summary> Sends the request in the pipeline message and returns the response. </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
ClientResult result = await GetNextResponseAsync(message).ConfigureAwait(false);
yield return result;

nextPageUri = ((ListWithNextLinkResponse)result).Next;
nextPageUri = ((ListWithNextLinkResult)result).Next;
if (nextPageUri == null)
{
yield break;
Expand All @@ -52,7 +52,7 @@ public override async IAsyncEnumerable<ClientResult> GetRawPagesAsync()
/// <returns> The continuation token for the specified page. </returns>
public override ContinuationToken GetContinuationToken(ClientResult page)
{
Uri nextPage = ((ListWithNextLinkResponse)page).Next;
Uri nextPage = ((ListWithNextLinkResult)page).Next;
if (nextPage != null)
{
return ContinuationToken.FromBytes(BinaryData.FromString(nextPage.IsAbsoluteUri ? nextPage.AbsoluteUri : nextPage.OriginalString));
Expand Down
Loading
Loading