Parcourir une collection à l’aide des Kits de développement logiciel (SDK) Microsoft Graph
Article
Pour des raisons de performances, les collections d’entités sont souvent divisées en pages et chaque page est retournée avec une URL vers la page suivante. La classe PageIterator simplifie l’utilisation des collections paginées.
PageIterator gère l’énumération de la page active et demande automatiquement les pages suivantes.
Si vous envoyez des en-têtes de requête supplémentaires dans votre demande initiale, ces en-têtes ne sont pas inclus par défaut dans les demandes de page suivantes. Si ces en-têtes doivent être envoyés sur les requêtes suivantes, vous devez les définir de manière explicite.
Itérer sur tous les messages
L’exemple suivant montre une itération sur tous les messages dans la boîte aux lettres d’un utilisateur.
Conseil
Cet exemple montre comment définir une petite taille de page à l’aide du top paramètre à des fins de démonstration. Vous pouvez définir la taille de page jusqu’à 999 pour réduire le nombre de demandes nécessaires.
const response: PageCollection = await graphClient
.api('/me/messages?$top=10&$select=sender,subject,body')
.header('Prefer', 'outlook.body-content-type="text"')
.get();
// A callback function to be called for every item in the collection.
// This call back should return boolean indicating whether not to
// continue the iteration process.
const callback: PageIteratorCallback = (message: Message) => {
console.log(message.subject);
return true;
};
// A set of request options to be applied to
// all subsequent page requests
const requestOptions: GraphRequestOptions = {
// Re-add the header to subsequent requests
headers: {
Prefer: 'outlook.body-content-type="text"',
},
};
// Creating a new page iterator instance with client a graph client
// instance, page collection response from request and callback
const pageIterator = new PageIterator(
graphClient,
response,
callback,
requestOptions,
);
// This iterates the collection until the nextLink is drained out.
await pageIterator.iterate();
Arrêt et reprise de l’itération
Certains scénarios nécessitent l’arrêt du processus d’itération pour effectuer d’autres actions. Il est possible de suspendre l’itération en retournant false à partir du rappel d’itération. L’itération peut être reprise en appelant la resume méthode sur le PageIterator.
var pageSize int32 = 10
query := users.ItemMessagesRequestBuilderGetQueryParameters{
Select: []string{"body", "sender", "subject"},
Top: &pageSize,
}
options := users.ItemMessagesRequestBuilderGetRequestConfiguration{
QueryParameters: &query,
}
result, err := graphClient.Me().Messages().Get(context.Background(), &options)
if err != nil {
log.Fatalf("Error getting messages: %v\n", err)
}
// Initialize iterator
pageIterator, err := graphcore.NewPageIterator[*models.Message](
result,
graphClient.GetAdapter(),
models.CreateMessageCollectionResponseFromDiscriminatorValue)
if err != nil {
log.Fatalf("Error creating page iterator: %v\n", err)
}
// Pause iterating after 25
var count, pauseAfter = 0, 25
// Iterate over all pages
err = pageIterator.Iterate(
context.Background(),
func(message *models.Message) bool {
count++
fmt.Printf("%d: %s\n", count, *message.GetSubject())
// Once count = 25, this returns false,
// Which pauses the iteration
return count < pauseAfter
})
if err != nil {
log.Fatalf("Error iterating over messages: %v\n", err)
}
// Pause 5 seconds
fmt.Printf("Iterated first %d messages, pausing for 5 seconds...\n", pauseAfter)
time.Sleep(5 * time.Second)
fmt.Printf("Resuming iteration...\n")
// Resume iteration
err = pageIterator.Iterate(
context.Background(),
func(message *models.Message) bool {
count++
fmt.Printf("%d: %s\n", count, *message.GetSubject())
// Return true to continue the iteration
return true
})
if err != nil {
log.Fatalf("Error iterating over messages: %v\n", err)
}
int iterations = 1;
ArrayList<Message> messages = new ArrayList<>();
int pauseAfter = iterations*25;
MessageCollectionResponse messageResponse = graphClient.me().messages().get( requestConfiguration -> {
requestConfiguration.queryParameters.top = 10;
requestConfiguration.queryParameters.select = new String[] {"sender, subject"};
});
PageIterator<Message, MessageCollectionResponse> pageIterator =
new PageIterator.Builder<Message, MessageCollectionResponse>()
.client(graphClient)
.collectionPage(Objects.requireNonNull(messageResponse))
.collectionPageFactory(MessageCollectionResponse::createFromDiscriminatorValue)
.requestConfigurator( requestInfo -> {
requestInfo.addQueryParameter("%24select", new String[] {"sender, subject"});
requestInfo.addQueryParameter("%24top", 10);
return requestInfo;
})
.processPageItemCallback( message -> {
messages.add(message);
// Pause paging by returning false after 25 messages
return messages.size() < pauseAfter;
}).build();
pageIterator.iterate();
// Resume paging
while (pageIterator.getPageIteratorState() != PageIterator.PageIteratorState.COMPLETE) {
iterations+=1;
pageIterator.resume();
}
$count = 0;
$messages = $graphClient->me()
->messages()
->get()
->wait();
// Microsoft\Graph\Core\Tasks\PageIterator
$pageIterator = new PageIterator($messages, $graphClient->getRequestAdapter());
$callback = function($message) use (&$count): bool {
/** @var Models\Message $message */
$count++;
print($count.'. '.$message->getSubject().PHP_EOL);
// Return true to continue iteration
// Return false once first 5 have been processed
return $count < 5;
};
$pageIterator->iterate($callback);
print('Pausing iteration after first 5'.PHP_EOL);
sleep(5);
// Process next 5
$count = 0;
$pageIterator->iterate($callback);
let count = 0;
const pauseAfter = 25;
const response: PageCollection = await graphClient
.api('/me/messages?$top=10&$select=sender,subject,body')
.get();
const callback: PageIteratorCallback = (message: Message) => {
console.log(message.subject);
count++;
// If we've iterated over the limit,
// stop the iteration by returning false
return count < pauseAfter;
};
const pageIterator = new PageIterator(graphClient, response, callback);
await pageIterator.iterate();
while (!pageIterator.isComplete()) {
console.log('Iteration paused for 5 seconds...');
await new Promise((resolve) => setTimeout(resolve, 5000));
// Reset count
count = 0;
await pageIterator.resume();
}
Demande manuelle des pages suivantes
En guise d’alternative à l’utilisation de la classe PageIterator, vous pouvez case activée manuellement la réponse d’une @odata.nextLink propriété et demander la page suivante.
var messages = await graphClient.Me.Messages
.GetAsync(requestConfiguration =>
{
requestConfiguration.QueryParameters.Top = 10;
});
while (messages?.Value != null)
{
foreach (var message in messages.Value)
{
Console.WriteLine(message.Subject);
}
// If OdataNextLink has a value, there is another page
if (!string.IsNullOrEmpty(messages.OdataNextLink))
{
// Pass the OdataNextLink to the WithUrl method
// to request the next page
messages = await graphClient.Me.Messages
.WithUrl(messages.OdataNextLink)
.GetAsync();
}
else
{
// No more results, exit loop
break;
}
}