如何将yield return与microsoft graph api v5 PageIterator一起使用

问题描述 投票:0回答:1

目前我正在使用 AsyncEnumerable 从 Graph API 获取组成员

public async IAsyncEnumerable<Microsoft.Graph.User> LoadGroupMembers(string GroupId)
{
    if (graphClient == null) throw new ArgumentNullException(nameof(graphClient));

    var users = await graphClient.Groups[GroupId].Members
        .Request()
        .GetAsync();

    var count = 0;    
    do
    {
        foreach (var member in users)
        {
            if (member is Microsoft.Graph.User user)
            {
                yield return user;
            }
        }
    }
    while (users.NextPageRequest != null && (users = await users.NextPageRequest.GetAsync()).Count > 0);
}

新的 v5 API 摆脱了 NextPageRequest 并用 PageIterator 代替。

var users = await graphClient.Groups[GroupId].Members
        .GetAsync();

var pageIterator = PageIterator<User,UserCollectionResponse>
    .CreatePageIterator(
        graphClient,
        users,
        // Callback executed for each item in the collection
        (u) =>
        {
            //Don't think I can yield return from here
            Console.WriteLine(u.UserName);
            return true;
        }
    );

await pageIterator.IterateAsync();

还有其他方法可以返回记录吗?

c# microsoft-graph-api
1个回答
0
投票

我使用以下内容来支持 SDK 版本 5,它借鉴了其他人的答案以及开箱即用的 PageIterator 类型中使用的内部概念(内部也使用了一些反射)。

public static class CollectionPageExtensions
{
    public static async IAsyncEnumerable<TEntity> AsAsyncEnumerable<TEntity, TCollectionPage>(this TCollectionPage collectionPage, IBaseClient graphClient, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        where TCollectionPage : IBackedModel, IParsable, IAdditionalDataHolder, new()
    {
        TCollectionPage? currentPage = collectionPage;
        do
        {
            var items = currentPage.BackingStore?.Get<List<TEntity>?>("value");

            foreach (TEntity? item in items)
            {
                cancellationToken.ThrowIfCancellationRequested();
                yield return item;
            }

            var nextPage = await currentPage.GetNextPageAsync<TEntity, TCollectionPage>(graphClient, cancellationToken).ConfigureAwait(false);
            if (nextPage == null)
            {
                yield break;
            }

            currentPage = nextPage;
        }
        while (currentPage is not null);
    }

    private static async Task<TCollectionPage?> GetNextPageAsync<TEntity, TCollectionPage>(this TCollectionPage collectionPage, IBaseClient graphClient, CancellationToken cancellationToken = default)
        where TCollectionPage : IBackedModel, IParsable, IAdditionalDataHolder, new()
    {
        var nextPageLink = ExtractNextLinkFromParsable(collectionPage);

        if (string.IsNullOrEmpty(nextPageLink))
        {
            return default;
        }

        // Call the MSGraph API to get the next page of results and set that page as the currentPage.
        var nextPageRequestInformation = new RequestInformation
        {
            HttpMethod = Method.GET,
            UrlTemplate = nextPageLink
        };
        // if we have a request configurator, modify the request as desired then execute it to get the next page
        return await graphClient.RequestAdapter.SendAsync(nextPageRequestInformation, (parseNode) => new TCollectionPage()).ConfigureAwait(false);
    }

    private static string ExtractNextLinkFromParsable<TCollectionPage>(TCollectionPage parsableCollection, string nextLinkPropertyName = "OdataNextLink")
        where TCollectionPage : IBackedModel, IParsable, IAdditionalDataHolder, new()
    {
        var nextLinkProperty = parsableCollection.GetType().GetProperty(nextLinkPropertyName);
        if (nextLinkProperty != null &&
            nextLinkProperty.GetValue(parsableCollection, null) is string nextLinkString
            && !string.IsNullOrEmpty(nextLinkString))
        {
            return nextLinkString;
        }

        if (parsableCollection.AdditionalData == null)
            return string.Empty;

        // the next link property may not be defined in the response schema so we also check its presence in the additional data bag
        if (parsableCollection.AdditionalData.TryGetValue(CoreConstants.OdataInstanceAnnotations.NextLink, out var nextLink))
        {
            if (nextLink != null)
                return nextLink.ToString();
        }
        return string.Empty;
    }
}

我还在这张票证中包含了此信息:https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/733#issuecomment-1884611064

© www.soinside.com 2019 - 2024. All rights reserved.