分页图数据

Paging Graph Data

我检查了 Stack 上的多个分页线程,但无法制作代码的功能副本。

我知道在下面的例子中,图表 returns 每页 200 项,如果我想要 foreach 所有的项目,我需要切换到下一页。请检查以下代码并告诉我我做错了什么。

总是在调用 NextPageRequest.GetAsync() 的捕获中抛出异常。

此代码的结果是仅删除了 3xx 项中的 200 项。

var deleteListItems = new List<Microsoft.Graph.ListItem>();
var deleteListItemsPage = await graphServiceClient
    .Sites[siteUrl]
    .Lists[listName]
    .Items
    .Request(deleteQueryOptions)
    .GetAsync();

deleteListItems.AddRange(deleteListItemsPage.CurrentPage);

do
{
    foreach (var deleteItem in deleteListItemsPage)
    {
        awaitTasks.Add(graphServiceClient
            .Sites[siteUrl]
            .Lists[listName]
            .Items[deleteItem.Id]
            .Request()
            .DeleteAsync());
    }

    try
    {
        Task.WaitAll(awaitTasks.ToArray());
    }
    catch
    {
        Console.WriteLine("ERROOR executing the tasks");
    }

    Console.WriteLine("Another PAGE of List Items successfully deleted");

    try
    {
        deleteListItemsPage = await deleteListItemsPage.NextPageRequest.GetAsync();
        deleteListItems.AddRange(deleteListItemsPage.CurrentPage);
    }
    catch
    {
        Console.WriteLine("There is no NextPageRequest for deleting items or ERROR occured.");
    }
} while (deleteListItemsPage.NextPageRequest != null);

几点观察:

  1. Task.WaitAll 模式在技术上是正确的,但在实践中,它很容易出现人为错误。您应该始终使用 async/await 模式,除非有非常令人信服的技术理由不这样做。它会让你省去很多麻烦。

  2. 你永远不应该使用空的 catch { } 子句,除非你想在没有警告或上下文的情况下吃掉任何异常(FTR,你 不要 想要这个)。至少,您应该捕获通用 System.Exception 并将其分配给一个变量 (catch (Exception e) {}),即使您使用它做的唯一事情是将异常记录到控制台 (catch (Exception e) { Console.WriteLine(e); }).

  3. 当你知道一个对象有可能成为null时,你应该总是检查 null而不是依赖一个Try/Catch。 Try/Catch 模式依赖于比简单的空检查贵 很多 的异常。

对于这样的场景,更好的模式应该是这样的:

private async Task DeleteItems()
{
    // Construct the HTTP Request but DO NOT execute it just yet
    var deleteListItemsRequest = graphServiceClient
        .Sites[siteUrl]
        .Lists[listName]
        .Items
        .Request(deleteQueryOptions);

    // This loop is for iterating over the pages
    do
    {
        // Populate the page by executing the HTTP request
        var deleteListItemsPage = deleteListItemsRequest.GetAsync();

        // Iterate over the current page
        foreach (var listItem in deleteListItemsPage.CurrentPage)
        {
            // Execute the delete and wait for the response
            await graphServiceClient
                .Sites[siteUrl]
                .Lists[listName]
                .Items[deleteItem.Id]
                .Request()
                .DeleteAsync();
        }

        // Check for additional pages
        if (deleteListItemsPage.NextPageRequest != null)
        {
            // If we have an additional page, assign it to the
            // same HTTP Request object. Again, we DO NOT execute 
            // yet. It will get executed at the top of the loop
            deleteListItemsRequest = deleteListItemsPage.NextPageRequest;
        }
        else
        {
            // If we don't have an additional page, set the current
            // request to null so we can use this to trigger an exit
            // from the loop
            deleteListItemsRequest = null;
        }

        // Check if we have a Graph request, if not break out of the loop
    } while (deleteListItemsRequest != null);
}