在C#控制台应用中结合Microsoft Graph批量请求与分页获取超900个用户的实现方案咨询
在C#控制台应用中结合Microsoft Graph批量请求与分页获取超900个用户的实现方案咨询
没问题,你的思路完全可行!我们完全可以把每个分页的用户查询请求加入批量请求中,一次性或分批次发送,最后合并所有分页的结果得到完整的用户列表。下面给你两种实用的实现方案,你可以根据自己的业务场景选择:
方案一:基于$skip/$top预生成批量请求(高效优先)
这种方式适合数据变化不频繁的场景,我们可以直接预先生成多个分页请求(每个请求跳过前面的N个用户),把它们全部加入批量请求后一次性或分批次发送,最后合并结果。优点是减少网络请求次数,效率更高;缺点是如果请求过程中用户数据有新增/删除,可能会出现重复或遗漏的情况。
代码示例
using Microsoft.Graph; using Microsoft.Graph.Models; using Microsoft.Kiota.Abstractions; // 初始化Graph客户端 var graphClient = new GraphServiceClient(interactiveCredential, scopes); var allUsers = new List<User>(); const int pageSize = 100; const int maxBatchRequests = 20; // Graph批量请求的单批次最大请求数限制 try { // 第一步:先获取总用户数,确定需要多少个分页请求 var countRequest = graphClient.Users.Count.ToGetRequestInformation(); var totalUsers = await graphClient.RequestAdapter.SendAsync(countRequest, long.CreateFromDiscriminatorValue); var totalPages = (int)Math.Ceiling(totalUsers / (double)pageSize); // 第二步:把分页请求分批次加入批量集合 var batchCollections = new List<BatchRequestContentCollection>(); var currentBatch = new BatchRequestContentCollection(graphClient); for (int pageIndex = 0; pageIndex < totalPages; pageIndex++) { var skip = pageIndex * pageSize; // 创建当前分页的请求信息,建议只获取需要的属性减少数据量 var pageRequest = graphClient.Users.ToGetRequestInformation(opt => { opt.QueryParameters.Top = pageSize; opt.QueryParameters.Skip = skip; opt.QueryParameters.Select = new[] { "id", "displayName", "mail" }; }); // 加入当前批次 await currentBatch.AddBatchRequestStepAsync(pageRequest); // 如果当前批次达到最大限制,就存入批次列表并新建批次 if ((pageIndex + 1) % maxBatchRequests == 0) { batchCollections.Add(currentBatch); currentBatch = new BatchRequestContentCollection(graphClient); } } // 把最后一个未填满的批次也加入列表 if (currentBatch.GetSteps().Any()) { batchCollections.Add(currentBatch); } // 第三步:执行所有批次的批量请求,收集结果 foreach (var batch in batchCollections) { var batchResponse = await graphClient.Batch.PostAsync(batch); foreach (var stepId in batchResponse.GetResponseIds()) { var pageResponse = await batchResponse.GetResponseByIdAsync<UserCollectionResponse>(stepId); if (pageResponse?.Value != null) { allUsers.AddRange(pageResponse.Value); } } } Console.WriteLine($"成功获取所有用户,总数量:{allUsers.Count}"); } catch (Exception ex) { Console.WriteLine($"请求过程中出现错误:{ex.Message}"); }
方案二:基于nextLink的动态批量分页(准确性优先)
如果你的业务场景对数据准确性要求极高(比如不允许出现重复或遗漏用户),那建议用这种方式。因为Graph返回的@odata.nextLink包含了分页的令牌,能保证数据的一致性,避免因数据变更导致的问题。
实现思路是:先获取第一页用户并拿到nextLink,然后把后续每个nextLink对应的请求加入批量(可以一次加入多个),执行批量后收集结果,再继续处理剩余的nextLink,直到没有下一页为止。
代码示例
using Microsoft.Graph; using Microsoft.Graph.Models; using Microsoft.Kiota.Abstractions; var graphClient = new GraphServiceClient(interactiveCredential, scopes); var allUsers = new List<User>(); const int batchSize = 5; // 每次批量发送5个分页请求 string nextLink = null; try { // 第一步:获取第一页用户 var firstPageRequest = graphClient.Users.ToGetRequestInformation(opt => { opt.QueryParameters.Select = new[] { "id", "displayName", "mail" }; }); var firstPageResponse = await graphClient.RequestAdapter.SendAsync(firstPageRequest, UserCollectionResponse.CreateFromDiscriminatorValue); allUsers.AddRange(firstPageResponse.Value); nextLink = firstPageResponse.OdataNextLink; // 第二步:循环处理剩余的分页,批量发送请求 while (!string.IsNullOrEmpty(nextLink)) { var currentBatch = new BatchRequestContentCollection(graphClient); var tempNextLinks = new List<string>(); tempNextLinks.Add(nextLink); // 收集足够数量的nextLink请求,或者直到没有下一页 for (int i = 1; i < batchSize && !string.IsNullOrEmpty(nextLink); i++) { var tempRequest = new RequestInformation { HttpMethod = Method.GET, Uri = new Uri(nextLink) }; var tempResponse = await graphClient.RequestAdapter.SendAsync(tempRequest, UserCollectionResponse.CreateFromDiscriminatorValue); tempNextLinks.Add(tempResponse.OdataNextLink); nextLink = tempResponse.OdataNextLink; } // 把收集到的nextLink请求加入批量 foreach (var link in tempNextLinks.Where(l => !string.IsNullOrEmpty(l))) { var pageRequest = new RequestInformation { HttpMethod = Method.GET, Uri = new Uri(link) }; await currentBatch.AddBatchRequestStepAsync(pageRequest); } // 执行批量请求并收集结果 var batchResponse = await graphClient.Batch.PostAsync(currentBatch); foreach (var stepId in batchResponse.GetResponseIds()) { var pageResponse = await batchResponse.GetResponseByIdAsync<UserCollectionResponse>(stepId); if (pageResponse?.Value != null) { allUsers.AddRange(pageResponse.Value); } } } Console.WriteLine($"成功获取所有用户,总数量:{allUsers.Count}"); } catch (Exception ex) { Console.WriteLine($"请求过程中出现错误:{ex.Message}"); }
额外提示
- 注意Microsoft Graph的批量请求单批次最多支持20个请求,所以两种方案都做了分批次处理的逻辑。
- 始终建议在请求中添加
$select参数,只获取你需要的用户属性,这样可以大幅减少数据传输量,提升请求速度。 - 如果不确定总用户数,方案一可以去掉获取总用户数的步骤,改成循环生成请求直到某个请求返回的用户数量小于
pageSize为止。
内容来源于stack exchange
相关产品推荐
相关产品推荐

