📄 MicrosoftLearnSearchProvider.cs
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Runtime.CompilerServices;
using System.Threading;
using MSearch.Domain;

namespace MSearch.SearchProviders.MicrosoftLearn;

internal sealed class MicrosoftLearnSearchProvider(HttpClient httpClient) : ISearchProvider
{
    public async IAsyncEnumerable<SearchResult> Search(
        SearchQuery query,
        [EnumeratorCancellation] CancellationToken cancellationToken
    )
    {
        var response = await httpClient.GetFromJsonAsync(
            $"https://learn.microsoft.com/api/search?locale=en-us%24top=10&%24filter=category%20eq%20%27Reference%27%20or%20category%20eq%20%27Documentation%27&search={Uri.EscapeDataString(query.Term)}",
            MicrosoftLearnJsonSerializerContext.Default.MicrosoftLearnSearchResponse,
            cancellationToken
        );
        if (response is null)
        {
            yield break;
        }
        foreach (var result in response.Results)
        {
            yield return Map(result);
        }
    }

    private static SearchResult Map(MicrosoftLearnSearchResult result) =>
        new(result.Title, result.Description, new(result.Url));
}