@@ -53,6 +53,79 @@ public async Task GoogleSearchAsync()
5353 }
5454 }
5555
56+ /// <summary>
57+ /// Show how to use <see cref="BingTextSearch"/> with the new generic <see cref="ITextSearch{TRecord}"/>
58+ /// interface and LINQ filtering for type-safe searches.
59+ /// </summary>
60+ [ Fact ]
61+ public async Task BingSearchWithLinqFilteringAsync ( )
62+ {
63+ // Create a BingTextSearch instance
64+ var bingSearch = new BingTextSearch ( apiKey : TestConfiguration . Bing . ApiKey ) ;
65+
66+ // Use the new generic interface for type-safe searches
67+ ITextSearch < BingWebPage > textSearch = bingSearch ;
68+
69+ var query = "What is the Semantic Kernel?" ;
70+
71+ // Use LINQ filtering for type-safe search with compile-time validation
72+ var options = new TextSearchOptions < BingWebPage >
73+ {
74+ Top = 4 ,
75+ Filter = page => page . Language == "en" && page . IsFamilyFriendly == true
76+ } ;
77+
78+ // Search and return strongly-typed results
79+ Console . WriteLine ( "\n --- Bing Search with LINQ Filtering ---\n " ) ;
80+ KernelSearchResults < BingWebPage > searchResults = await textSearch . GetSearchResultsAsync ( query , options ) ;
81+ await foreach ( BingWebPage page in searchResults . Results )
82+ {
83+ Console . WriteLine ( $ "Name: { page . Name } ") ;
84+ Console . WriteLine ( $ "Snippet: { page . Snippet } ") ;
85+ Console . WriteLine ( $ "Url: { page . Url } ") ;
86+ Console . WriteLine ( $ "Language: { page . Language } ") ;
87+ Console . WriteLine ( $ "Family Friendly: { page . IsFamilyFriendly } ") ;
88+ Console . WriteLine ( "---" ) ;
89+ }
90+ }
91+
92+ /// <summary>
93+ /// Show how to use <see cref="GoogleTextSearch"/> with the new generic <see cref="ITextSearch{TRecord}"/>
94+ /// interface and LINQ filtering for type-safe searches.
95+ /// </summary>
96+ [ Fact ]
97+ public async Task GoogleSearchWithLinqFilteringAsync ( )
98+ {
99+ // Create a GoogleTextSearch instance
100+ var googleSearch = new GoogleTextSearch (
101+ searchEngineId : TestConfiguration . Google . SearchEngineId ,
102+ apiKey : TestConfiguration . Google . ApiKey ) ;
103+
104+ // Use the new generic interface for type-safe searches
105+ ITextSearch < GoogleWebPage > textSearch = googleSearch ;
106+
107+ var query = "What is the Semantic Kernel?" ;
108+
109+ // Use LINQ filtering for type-safe search with compile-time validation
110+ var options = new TextSearchOptions < GoogleWebPage >
111+ {
112+ Top = 4 ,
113+ Filter = page => page . Title . Contains ( "Semantic" ) && page . DisplayLink . EndsWith ( ".com" )
114+ } ;
115+
116+ // Search and return strongly-typed results
117+ Console . WriteLine ( "\n --- Google Search with LINQ Filtering ---\n " ) ;
118+ KernelSearchResults < GoogleWebPage > searchResults = await textSearch . GetSearchResultsAsync ( query , options ) ;
119+ await foreach ( GoogleWebPage page in searchResults . Results )
120+ {
121+ Console . WriteLine ( $ "Title: { page . Title } ") ;
122+ Console . WriteLine ( $ "Snippet: { page . Snippet } ") ;
123+ Console . WriteLine ( $ "Link: { page . Link } ") ;
124+ Console . WriteLine ( $ "Display Link: { page . DisplayLink } ") ;
125+ Console . WriteLine ( "---" ) ;
126+ }
127+ }
128+
56129 /// <summary>
57130 /// Show how to create a <see cref="BingTextSearch"/> and use it to perform a search
58131 /// and return results as a collection of <see cref="BingWebPage"/> instances.
@@ -86,7 +159,7 @@ public async Task SearchForWebPagesAsync()
86159 }
87160 else
88161 {
89- Console . WriteLine ( "\n ——— Google Web Page Results ——— \n " ) ;
162+ Console . WriteLine ( "\n ��� Google Web Page Results ��� \n " ) ;
90163 await foreach ( Google . Apis . CustomSearchAPI . v1 . Data . Result result in objectResults . Results )
91164 {
92165 Console . WriteLine ( $ "Title: { result . Title } ") ;
@@ -129,119 +202,4 @@ public async Task SearchForTextSearchResultsAsync()
129202 Console . WriteLine ( $ "Link: { result . Link } ") ;
130203 }
131204 }
132-
133- /// <summary>
134- /// Show how to use the new generic <see cref="ITextSearch{TRecord}"/> interface with LINQ filtering for type-safe searches.
135- /// This demonstrates the modernized text search functionality introduced in Issue #10456.
136- /// </summary>
137- /// <remarks>
138- /// This example shows the intended pattern for the new generic interfaces.
139- /// Currently demonstrates the concept using examples from the existing connectors in this sample suite:
140- /// - BingTextSearch and GoogleTextSearch (this file)
141- /// - VectorStoreTextSearch (Step4_Search_With_VectorStore.cs)
142- /// </remarks>
143- [ Fact ]
144- public Task SearchWithLinqFilteringAsync ( )
145- {
146- // This example demonstrates the NEW generic interface pattern with LINQ filtering
147- // that provides compile-time type safety and IntelliSense support
148-
149- Console . WriteLine ( "\n --- Type-Safe Search with Generic Interface and LINQ Filtering ---\n " ) ;
150- Console . WriteLine ( "This demonstrates the modernized ITextSearch<TRecord> pattern from Issue #10456" ) ;
151- Console . WriteLine ( "Key benefits:" ) ;
152- Console . WriteLine ( "- Compile-time type safety (no runtime errors from property name typos)" ) ;
153- Console . WriteLine ( "- IntelliSense support for filtering properties" ) ;
154- Console . WriteLine ( "- LINQ expressions for complex filtering logic" ) ;
155- Console . WriteLine ( "- Better developer experience with strongly-typed search results" ) ;
156- Console . WriteLine ( ) ;
157-
158- Console . WriteLine ( "=== Connectors Available in This Sample Suite ===" ) ;
159- Console . WriteLine ( ) ;
160-
161- Console . WriteLine ( "1. VectorStoreTextSearch<TRecord> (Step4_Search_With_VectorStore.cs)" ) ;
162- Console . WriteLine ( " [OK] Already implements ITextSearch<TRecord> with LINQ filtering:" ) ;
163- Console . WriteLine ( " var vectorSearch = new VectorStoreTextSearch<DataModel>(collection);" ) ;
164- Console . WriteLine ( " var options = new TextSearchOptions<DataModel>" ) ;
165- Console . WriteLine ( " {" ) ;
166- Console . WriteLine ( " Filter = record => record.Tag == \" Technology\" && record.Title.Contains(\" AI\" )" ) ;
167- Console . WriteLine ( " };" ) ;
168- Console . WriteLine ( " var results = await vectorSearch.GetSearchResultsAsync(query, options);" ) ;
169- Console . WriteLine ( ) ;
170-
171- if ( this . UseBingSearch )
172- {
173- Console . WriteLine ( "2. BingTextSearch (this file - BingSearchAsync())" ) ;
174- Console . WriteLine ( " [PLANNED] Pattern for future generic interface (once PR3 is merged):" ) ;
175- Console . WriteLine ( " var bingSearch = new BingTextSearch(apiKey);" ) ;
176- Console . WriteLine ( " var options = new TextSearchOptions<BingWebPage>" ) ;
177- Console . WriteLine ( " {" ) ;
178- Console . WriteLine ( " Top = 4," ) ;
179- Console . WriteLine ( " Filter = page => page.Name.Contains(\" Microsoft\" ) && page.Snippet.Contains(\" AI\" )" ) ;
180- Console . WriteLine ( " };" ) ;
181- Console . WriteLine ( " var results = await ((ITextSearch<BingWebPage>)bingSearch).GetSearchResultsAsync(query, options);" ) ;
182- Console . WriteLine ( " // Type-safe access: page.Name, page.Snippet, page.Url, page.DateLastCrawled" ) ;
183- }
184- else
185- {
186- Console . WriteLine ( "2. BingTextSearch (set UseBingSearch = true to see example)" ) ;
187- }
188-
189- Console . WriteLine ( ) ;
190- Console . WriteLine ( "3. GoogleTextSearch (this file - GoogleSearchAsync())" ) ;
191- Console . WriteLine ( " [PLANNED] Pattern for future generic interface (once PR4 is merged):" ) ;
192- Console . WriteLine ( " // Note: GoogleWebPage is a conceptual type pending PR4 implementation" ) ;
193- Console . WriteLine ( " // The actual Google API currently uses: Google.Apis.CustomSearchAPI.v1.Data.Result" ) ;
194- Console . WriteLine ( " var googleSearch = new GoogleTextSearch(searchEngineId, apiKey);" ) ;
195- Console . WriteLine ( " var options = new TextSearchOptions<GoogleWebPage>" ) ;
196- Console . WriteLine ( " {" ) ;
197- Console . WriteLine ( " Top = 4," ) ;
198- Console . WriteLine ( " Filter = page => page.Title.Contains(\" AI\" ) && page.DisplayLink.EndsWith(\" .com\" )" ) ;
199- Console . WriteLine ( " };" ) ;
200- Console . WriteLine ( " var results = await ((ITextSearch<GoogleWebPage>)googleSearch).GetSearchResultsAsync(query, options);" ) ;
201- Console . WriteLine ( " // Type-safe access: page.Title, page.Snippet, page.DisplayLink, page.Link" ) ;
202- Console . WriteLine ( ) ;
203-
204- Console . WriteLine ( "=== Key Technical Benefits ===" ) ;
205- Console . WriteLine ( ) ;
206- Console . WriteLine ( "[OK] Compile-time validation - no more runtime property name errors" ) ;
207- Console . WriteLine ( "[OK] IntelliSense support - IDE shows available properties for each connector" ) ;
208- Console . WriteLine ( "[OK] Type safety - strongly typed search results and filtering" ) ;
209- Console . WriteLine ( "[OK] LINQ expressions - familiar &&, ||, Contains(), StartsWith(), comparisons, etc." ) ;
210- Console . WriteLine ( "[OK] C# version compatibility - expressions work across C# 12, 13, and 14+" ) ;
211- Console . WriteLine ( "[OK] 100% backward compatibility - existing ITextSearch code unchanged" ) ;
212- Console . WriteLine ( ) ;
213-
214- Console . WriteLine ( "=== Example LINQ Filtering Patterns ===" ) ;
215- Console . WriteLine ( ) ;
216- Console . WriteLine ( "// Bing: Filter web pages by content and metadata" ) ;
217- Console . WriteLine ( "Filter = page => page.Name.Contains(\" Microsoft\" ) && page.DateLastCrawled > DateTime.Now.AddDays(-7)" ) ;
218- Console . WriteLine ( "// ↑ String.Contains (instance method) - works in all C# versions" ) ;
219- Console . WriteLine ( ) ;
220- Console . WriteLine ( "// Google: Filter search results by domain and content" ) ;
221- Console . WriteLine ( "Filter = result => result.Title.Contains(\" AI\" ) && result.DisplayLink.EndsWith(\" .edu\" )" ) ;
222- Console . WriteLine ( "// ↑ String.Contains (instance method) - works in all C# versions" ) ;
223- Console . WriteLine ( ) ;
224- Console . WriteLine ( "// Vector Store: Filter custom record types with complex logic" ) ;
225- Console . WriteLine ( "Filter = record => record.Category == \" Technology\" && record.Score > 0.75 && record.Tags.Any(t => t == \" AI\" )" ) ;
226- Console . WriteLine ( "// ↑ Use Any() for collections" ) ;
227- Console . WriteLine ( ) ;
228- Console . WriteLine ( "// C# 14 Compatibility Note:" ) ;
229- Console . WriteLine ( "// - String.Contains() (instance method): ✅ Works in all C# versions" ) ;
230- Console . WriteLine ( "// - For collection filtering, use Any() or Where(): array.Any(x => x == value)" ) ;
231- Console . WriteLine ( "// - Avoid collection.Contains(item) in expressions (C# 14 resolution changes)" ) ;
232- Console . WriteLine ( ) ;
233-
234- Console . WriteLine ( "The VectorStoreTextSearch already demonstrates this pattern in Step4!" ) ;
235- Console . WriteLine ( "See Step4_Search_With_VectorStore.cs for working generic interface examples." ) ;
236- Console . WriteLine ( ) ;
237- Console . WriteLine ( "This modernization is part of the structured PR series for Issue #10456:" ) ;
238- Console . WriteLine ( "PR1: Core generic interfaces [OK]" ) ;
239- Console . WriteLine ( "PR2: VectorStoreTextSearch implementation [OK]" ) ;
240- Console . WriteLine ( "PR3: BingTextSearch connector (future) [PLANNED]" ) ;
241- Console . WriteLine ( "PR4: GoogleTextSearch connector (future) [PLANNED]" ) ;
242- Console . WriteLine ( "PR5: TavilyTextSearch & BraveTextSearch connectors (future) [PLANNED]" ) ;
243- Console . WriteLine ( "PR6: Samples and documentation (this PR) [OK]" ) ;
244-
245- return Task . CompletedTask ;
246- }
247205}
0 commit comments