11using System . Text . Json ;
2+ using System . Text . Json . Serialization . Metadata ;
23using Microsoft . Extensions . VectorData ;
34
45namespace EasyAppDev . Blazor . AutoComplete . AI . AzureSearch . Models ;
@@ -8,6 +9,10 @@ namespace EasyAppDev.Blazor.AutoComplete.AI.AzureSearch.Models;
89/// The TItem is serialized as JSON for flexible storage.
910/// Note: Must be public for Azure Search SDK JSON serialization to work.
1011/// </summary>
12+ /// <remarks>
13+ /// For AOT compatibility, use the overloads that accept <see cref="JsonSerializerOptions"/>
14+ /// or <see cref="JsonTypeInfo{T}"/> with a source-generated context.
15+ /// </remarks>
1116public sealed class AzureSearchVectorRecord
1217{
1318 /// <summary>
@@ -36,7 +41,7 @@ public sealed class AzureSearchVectorRecord
3641
3742 /// <summary>
3843 /// The embedding vector.
39- /// Dimensions are configured at runtime.
44+ /// Dimensions are configured at runtime via VectorStoreCollectionDefinition .
4045 /// </summary>
4146 [ VectorStoreVector ( Dimensions : 1536 , DistanceFunction = DistanceFunction . CosineSimilarity ) ]
4247 public required ReadOnlyMemory < float > Embedding { get ; init ; }
@@ -45,13 +50,73 @@ public sealed class AzureSearchVectorRecord
4550 /// Deserializes the item from JSON.
4651 /// </summary>
4752 /// <typeparam name="TItem">The item type to deserialize to.</typeparam>
48- /// <returns>The deserialized item, or null if deserialization fails.</returns>
53+ /// <returns>The deserialized item, or default if deserialization fails.</returns>
54+ /// <remarks>
55+ /// This method uses reflection-based deserialization and is NOT AOT-compatible.
56+ /// For AOT scenarios, use <see cref="GetItem{TItem}(JsonSerializerOptions)"/> or
57+ /// <see cref="GetItem{TItem}(JsonTypeInfo{TItem})"/> instead.
58+ /// </remarks>
4959 public TItem ? GetItem < TItem > ( )
60+ {
61+ return GetItemCore < TItem > ( null , null ) ;
62+ }
63+
64+ /// <summary>
65+ /// Deserializes the item from JSON using the specified options.
66+ /// </summary>
67+ /// <typeparam name="TItem">The item type to deserialize to.</typeparam>
68+ /// <param name="options">JSON serializer options with a configured TypeInfoResolver for AOT compatibility.</param>
69+ /// <returns>The deserialized item, or default if deserialization fails.</returns>
70+ /// <remarks>
71+ /// For AOT compatibility, configure options with a source-generated JsonSerializerContext:
72+ /// <code>
73+ /// var options = new JsonSerializerOptions { TypeInfoResolver = MyJsonContext.Default };
74+ /// var item = record.GetItem<MyType>(options);
75+ /// </code>
76+ /// </remarks>
77+ public TItem ? GetItem < TItem > ( JsonSerializerOptions options )
78+ {
79+ ArgumentNullException . ThrowIfNull ( options ) ;
80+ return GetItemCore < TItem > ( options , null ) ;
81+ }
82+
83+ /// <summary>
84+ /// Deserializes the item from JSON using the specified type info.
85+ /// </summary>
86+ /// <typeparam name="TItem">The item type to deserialize to.</typeparam>
87+ /// <param name="jsonTypeInfo">The JSON type info from a source-generated context.</param>
88+ /// <returns>The deserialized item, or default if deserialization fails.</returns>
89+ /// <remarks>
90+ /// This is the preferred method for AOT-compatible deserialization:
91+ /// <code>
92+ /// var item = record.GetItem(MyJsonContext.Default.MyType);
93+ /// </code>
94+ /// </remarks>
95+ public TItem ? GetItem < TItem > ( JsonTypeInfo < TItem > jsonTypeInfo )
96+ {
97+ ArgumentNullException . ThrowIfNull ( jsonTypeInfo ) ;
98+ return GetItemCore < TItem > ( null , jsonTypeInfo ) ;
99+ }
100+
101+ private TItem ? GetItemCore < TItem > ( JsonSerializerOptions ? options , JsonTypeInfo < TItem > ? jsonTypeInfo )
50102 {
51103 if ( string . IsNullOrEmpty ( ItemJson ) )
52104 return default ;
53105
54- return JsonSerializer . Deserialize < TItem > ( ItemJson ) ;
106+ try
107+ {
108+ if ( jsonTypeInfo is not null )
109+ return JsonSerializer . Deserialize ( ItemJson , jsonTypeInfo ) ;
110+
111+ if ( options is not null )
112+ return JsonSerializer . Deserialize < TItem > ( ItemJson , options ) ;
113+
114+ return JsonSerializer . Deserialize < TItem > ( ItemJson ) ;
115+ }
116+ catch ( JsonException )
117+ {
118+ return default ;
119+ }
55120 }
56121
57122 /// <summary>
@@ -64,17 +129,94 @@ public sealed class AzureSearchVectorRecord
64129 /// <param name="title">Optional title for filtering.</param>
65130 /// <param name="embedding">The embedding vector.</param>
66131 /// <returns>A new AzureSearchVectorRecord instance.</returns>
132+ /// <remarks>
133+ /// This method uses reflection-based serialization and is NOT AOT-compatible.
134+ /// For AOT scenarios, use <see cref="Create{TItem}(string, TItem, string, string?, ReadOnlyMemory{float}, JsonSerializerOptions)"/>
135+ /// or <see cref="Create{TItem}(string, TItem, string, string?, ReadOnlyMemory{float}, JsonTypeInfo{TItem})"/> instead.
136+ /// </remarks>
67137 public static AzureSearchVectorRecord Create < TItem > (
68138 string id ,
69139 TItem item ,
70140 string content ,
71141 string ? title ,
72142 ReadOnlyMemory < float > embedding )
73143 {
144+ return CreateCore ( id , item , content , title , embedding , null , null ) ;
145+ }
146+
147+ /// <summary>
148+ /// Creates an AzureSearchVectorRecord from an item using the specified options.
149+ /// </summary>
150+ /// <typeparam name="TItem">The item type.</typeparam>
151+ /// <param name="id">Unique identifier.</param>
152+ /// <param name="item">The item to store.</param>
153+ /// <param name="content">Text content for full-text search.</param>
154+ /// <param name="title">Optional title for filtering.</param>
155+ /// <param name="embedding">The embedding vector.</param>
156+ /// <param name="options">JSON serializer options with a configured TypeInfoResolver for AOT compatibility.</param>
157+ /// <returns>A new AzureSearchVectorRecord instance.</returns>
158+ public static AzureSearchVectorRecord Create < TItem > (
159+ string id ,
160+ TItem item ,
161+ string content ,
162+ string ? title ,
163+ ReadOnlyMemory < float > embedding ,
164+ JsonSerializerOptions options )
165+ {
166+ ArgumentNullException . ThrowIfNull ( options ) ;
167+ return CreateCore ( id , item , content , title , embedding , options , null ) ;
168+ }
169+
170+ /// <summary>
171+ /// Creates an AzureSearchVectorRecord from an item using the specified type info.
172+ /// </summary>
173+ /// <typeparam name="TItem">The item type.</typeparam>
174+ /// <param name="id">Unique identifier.</param>
175+ /// <param name="item">The item to store.</param>
176+ /// <param name="content">Text content for full-text search.</param>
177+ /// <param name="title">Optional title for filtering.</param>
178+ /// <param name="embedding">The embedding vector.</param>
179+ /// <param name="jsonTypeInfo">The JSON type info from a source-generated context.</param>
180+ /// <returns>A new AzureSearchVectorRecord instance.</returns>
181+ /// <remarks>
182+ /// This is the preferred method for AOT-compatible serialization:
183+ /// <code>
184+ /// var record = AzureSearchVectorRecord.Create(id, item, content, title, embedding, MyJsonContext.Default.MyType);
185+ /// </code>
186+ /// </remarks>
187+ public static AzureSearchVectorRecord Create < TItem > (
188+ string id ,
189+ TItem item ,
190+ string content ,
191+ string ? title ,
192+ ReadOnlyMemory < float > embedding ,
193+ JsonTypeInfo < TItem > jsonTypeInfo )
194+ {
195+ ArgumentNullException . ThrowIfNull ( jsonTypeInfo ) ;
196+ return CreateCore ( id , item , content , title , embedding , null , jsonTypeInfo ) ;
197+ }
198+
199+ private static AzureSearchVectorRecord CreateCore < TItem > (
200+ string id ,
201+ TItem item ,
202+ string content ,
203+ string ? title ,
204+ ReadOnlyMemory < float > embedding ,
205+ JsonSerializerOptions ? options ,
206+ JsonTypeInfo < TItem > ? jsonTypeInfo )
207+ {
208+ string itemJson ;
209+ if ( jsonTypeInfo is not null )
210+ itemJson = JsonSerializer . Serialize ( item , jsonTypeInfo ) ;
211+ else if ( options is not null )
212+ itemJson = JsonSerializer . Serialize ( item , options ) ;
213+ else
214+ itemJson = JsonSerializer . Serialize ( item ) ;
215+
74216 return new AzureSearchVectorRecord
75217 {
76218 Id = id ,
77- ItemJson = JsonSerializer . Serialize ( item ) ,
219+ ItemJson = itemJson ,
78220 Content = content ,
79221 Title = title ,
80222 Embedding = embedding
0 commit comments