Skip to content

Commit 0789cfd

Browse files
authored
Add AOT-compatible Search<T> API (Azure#51770)
1 parent d994570 commit 0789cfd

File tree

11 files changed

+621
-179
lines changed

11 files changed

+621
-179
lines changed

sdk/search/Azure.Search.Documents/CHANGELOG.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
# Release History
22

3-
## 11.7.0-beta.6 (Unreleased)
3+
## 11.7.0-beta.6 (2025-08-11)
44

55
### Features Added
66

77
- Enable the new model serialization using System.ClientModel, refer to this [document](https://aka.ms/azsdk/net/mrw) for more details.
8-
9-
### Breaking Changes
10-
11-
### Bugs Fixed
12-
13-
### Other Changes
8+
- Added new AOT-compatible overloads for `Search<T>` and `SearchAsync<T>` that take `JsonTypeInfo<T>`.
149

1510
## 11.6.1 (2025-06-17)
1611

sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.net8.0.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ public SearchClient(System.Uri endpoint, string indexName, Azure.Core.TokenCrede
8585
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(Azure.Search.Documents.SearchOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8686
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(string searchText, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8787
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(string searchText, string querySourceAuthorization, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
88+
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(string searchText, System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> typeInfo, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8889
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(Azure.Search.Documents.SearchOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8990
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(string searchText, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9091
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(string searchText, string querySourceAuthorization, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
92+
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(string searchText, System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> typeInfo, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9193
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SuggestResults<T>>> SuggestAsync<T>(string searchText, string suggesterName, Azure.Search.Documents.SuggestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9294
public virtual Azure.Response<Azure.Search.Documents.Models.SuggestResults<T>> Suggest<T>(string searchText, string suggesterName, Azure.Search.Documents.SuggestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9395
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.IndexDocumentsResult>> UploadDocumentsAsync<T>(System.Collections.Generic.IEnumerable<T> documents, Azure.Search.Documents.IndexDocumentsOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
@@ -5724,7 +5726,7 @@ internal SearchResultsPage() { }
57245726
public override System.Collections.Generic.IReadOnlyList<Azure.Search.Documents.Models.SearchResult<T>> Values { get { throw null; } }
57255727
public override Azure.Response GetRawResponse() { throw null; }
57265728
}
5727-
public partial class SearchResults<T>
5729+
public abstract partial class SearchResults<T>
57285730
{
57295731
internal SearchResults() { }
57305732
public double? Coverage { get { throw null; } }

sdk/search/Azure.Search.Documents/api/Azure.Search.Documents.netstandard2.0.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ public SearchClient(System.Uri endpoint, string indexName, Azure.Core.TokenCrede
8585
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(Azure.Search.Documents.SearchOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8686
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(string searchText, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8787
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(string searchText, string querySourceAuthorization, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
88+
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SearchResults<T>>> SearchAsync<T>(string searchText, System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> typeInfo, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8889
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(Azure.Search.Documents.SearchOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
8990
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(string searchText, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9091
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(string searchText, string querySourceAuthorization, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
92+
public virtual Azure.Response<Azure.Search.Documents.Models.SearchResults<T>> Search<T>(string searchText, System.Text.Json.Serialization.Metadata.JsonTypeInfo<T> typeInfo, Azure.Search.Documents.SearchOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9193
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.SuggestResults<T>>> SuggestAsync<T>(string searchText, string suggesterName, Azure.Search.Documents.SuggestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9294
public virtual Azure.Response<Azure.Search.Documents.Models.SuggestResults<T>> Suggest<T>(string searchText, string suggesterName, Azure.Search.Documents.SuggestOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
9395
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Search.Documents.Models.IndexDocumentsResult>> UploadDocumentsAsync<T>(System.Collections.Generic.IEnumerable<T> documents, Azure.Search.Documents.IndexDocumentsOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
@@ -5724,7 +5726,7 @@ internal SearchResultsPage() { }
57245726
public override System.Collections.Generic.IReadOnlyList<Azure.Search.Documents.Models.SearchResult<T>> Values { get { throw null; } }
57255727
public override Azure.Response GetRawResponse() { throw null; }
57265728
}
5727-
public partial class SearchResults<T>
5729+
public abstract partial class SearchResults<T>
57285730
{
57295731
internal SearchResults() { }
57305732
public double? Coverage { get { throw null; } }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# SearchResults<T> can safely be made abstract because it has no public constructors
2+
CannotMakeTypeAbstract : Type 'Azure.Search.Documents.Models.SearchResults<T>' is abstract in the implementation but is not abstract in the contract.

sdk/search/Azure.Search.Documents/src/Models/SearchResult.cs

Lines changed: 86 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
using System.Collections.Generic;
55
using System.ComponentModel;
66
using System.Diagnostics;
7+
using System.Diagnostics.CodeAnalysis;
78
using System.IO;
89
using System.Text.Json;
10+
using System.Text.Json.Serialization.Metadata;
911
using System.Threading;
1012
using System.Threading.Tasks;
1113
using Azure.Core;
@@ -77,6 +79,7 @@ internal SearchResult() { }
7779
/// that the operation should be canceled.
7880
/// </param>
7981
/// <returns>Deserialized SearchResults.</returns>
82+
[RequiresUnreferencedCode(JsonSerialization.TrimWarning)]
8083
internal static async Task<SearchResult<T>> DeserializeAsync(
8184
JsonElement element,
8285
ObjectSerializer serializer,
@@ -86,6 +89,89 @@ internal static async Task<SearchResult<T>> DeserializeAsync(
8689
#pragma warning restore CS1572
8790
{
8891
Debug.Assert(options != null);
92+
SearchResult<T> result = DeserializeEnvelope(element);
93+
94+
// Deserialize the model
95+
if (serializer != null)
96+
{
97+
using Stream stream = element.ToStream();
98+
T document = async ?
99+
(T)await serializer.DeserializeAsync(stream, typeof(T), cancellationToken).ConfigureAwait(false) :
100+
(T)serializer.Deserialize(stream, typeof(T), cancellationToken);
101+
result.Document = document;
102+
}
103+
else
104+
{
105+
T document;
106+
if (async)
107+
{
108+
using Stream stream = element.ToStream();
109+
document = await JsonSerializer.DeserializeAsync<T>(stream, options, cancellationToken).ConfigureAwait(false);
110+
}
111+
else
112+
{
113+
document = JsonSerializer.Deserialize<T>(element.GetRawText(), options);
114+
}
115+
result.Document = document;
116+
}
117+
118+
return result;
119+
}
120+
121+
/// <summary>
122+
/// Deserialize a SearchResult and its model.
123+
/// </summary>
124+
/// <param name="element">A JSON element.</param>
125+
/// <param name="serializer">
126+
/// Optional serializer that can be used to customize the serialization
127+
/// of strongly typed models.
128+
/// </param>
129+
/// <param name="typeInfo">Metadata about the type to deserialize.</param>
130+
/// <param name="async">Whether to execute sync or async.</param>
131+
/// <param name="cancellationToken">
132+
/// Optional <see cref="CancellationToken"/> to propagate notifications
133+
/// that the operation should be canceled.
134+
/// </param>
135+
/// <returns>Deserialized SearchResults.</returns>
136+
internal static async Task<SearchResult<T>> DeserializeAsync(
137+
JsonElement element,
138+
ObjectSerializer serializer,
139+
JsonTypeInfo<T> typeInfo,
140+
bool async,
141+
CancellationToken cancellationToken)
142+
#pragma warning restore CS1572
143+
{
144+
Debug.Assert(typeInfo != null);
145+
SearchResult<T> result = DeserializeEnvelope(element);
146+
// Deserialize the model
147+
if (serializer != null)
148+
{
149+
using Stream stream = element.ToStream();
150+
T document = async ?
151+
(T)await serializer.DeserializeAsync(stream, typeof(T), cancellationToken).ConfigureAwait(false) :
152+
(T)serializer.Deserialize(stream, typeof(T), cancellationToken);
153+
result.Document = document;
154+
}
155+
else
156+
{
157+
T document;
158+
if (async)
159+
{
160+
using Stream stream = element.ToStream();
161+
document = await JsonSerializer.DeserializeAsync<T>(stream, typeInfo, cancellationToken).ConfigureAwait(false);
162+
}
163+
else
164+
{
165+
document = JsonSerializer.Deserialize<T>(element.GetRawText(), typeInfo);
166+
}
167+
result.Document = document;
168+
}
169+
170+
return result;
171+
}
172+
173+
private static SearchResult<T> DeserializeEnvelope(JsonElement element)
174+
{
89175
SearchResult<T> result = new SearchResult<T>();
90176
result.SemanticSearch = new SemanticSearchResult();
91177
foreach (JsonProperty prop in element.EnumerateObject())
@@ -136,30 +222,6 @@ internal static async Task<SearchResult<T>> DeserializeAsync(
136222
}
137223
}
138224

139-
// Deserialize the model
140-
if (serializer != null)
141-
{
142-
using Stream stream = element.ToStream();
143-
T document = async ?
144-
(T)await serializer.DeserializeAsync(stream, typeof(T), cancellationToken).ConfigureAwait(false) :
145-
(T)serializer.Deserialize(stream, typeof(T), cancellationToken);
146-
result.Document = document;
147-
}
148-
else
149-
{
150-
T document;
151-
if (async)
152-
{
153-
using Stream stream = element.ToStream();
154-
document = await JsonSerializer.DeserializeAsync<T>(stream, options, cancellationToken).ConfigureAwait(false);
155-
}
156-
else
157-
{
158-
document = JsonSerializer.Deserialize<T>(element.GetRawText(), options);
159-
}
160-
result.Document = document;
161-
}
162-
163225
return result;
164226
}
165227
}

0 commit comments

Comments
 (0)