Seitensuchen mithilfe von EWS in Exchange durchführen
Lernen Sie, wie Sie Seitensuchen in Ihrem verwalteten EWS-API oder EWS-Anwendung, die auf Exchange zielen, durchführen können.
Das Paging ist ein Feature in EWS, das es Ihnen ermöglicht, die Größe der Ergebnisse einer Suche zu steuern. Statt das ganze Resultset in einer EWS-Antwort abzurufen, können Sie kleinere Sets in mehreren EWS-Antworten abrufen. Erwägen Sie z.B. einen Benutzer, der 10 000 Emails in seinem Posteingang hat. Hypothetisch könnten Sie alle 10 000 Emails in einer einzigen sehr großen Antwort abrufen, Sie könnten es jedoch in mehrere übersichtlichere Teile trennen wollen, um eine bessere Bandbreite und Leistung zu gewährleisten. Das Paging bietet Ihnen die Tools um genau das machen zu können.
Hinweis
Sie können zwar hypothetisch 10 000 Elemente in einer Anforderung abrufen, tatsächlich ist es jedoch wegen der EWS-Drosselung unwahrscheinlich. Weiter Informationen finden Sie unter EWS-Drosselung in Exchange.
Tabelle 1. Pagingparameter in der verwalteten EWS-API und EWS
Um die... zu konfigurieren und abzurufen | Verwalten Sie in der verwalteten EWS-API... | Verwalten Sie in EWS... |
---|---|---|
Maximale Anzahl von Elementen oder Ordnern in einer Antwort |
Die pageSize-Parameter zum ItemView-Konstruktor oder dem FolderView-Konstruktor Oder Die PagedView.PageSize-Eigenschaft |
Das MaxEntriesReturned-Attribut auf dem IndexedPageItemView-Element oder das IndexedPageFolderView-Element |
Ausgangspunkt in der Liste der Elemente oder Ordner |
Die offsetBasePoint-Parameter zum ItemView-Konstruktor oder dem FolderView-Konstruktor Oder Die PagedView.OffsetBasePoint-Eigenschaft |
Das BasePoint-Attribut auf dem IndexedPageItemView-Element oder das IndexedPageFolderView-Element |
Offset vom Ausgangspunkt |
Das Offset-Parameter zum ItemView-Konstruktor oder dem FolderView-Konstruktor Oder Die PagedView.Offset-Eigenschaft |
Das Offset-Attribut auf dem IndexedPageItemView-Element oder das IndexedPageFolderView-Element |
Gesamtnummer der Ergebnisse auf dem Server |
Die FindItemsResults.TotalCount-Eigenschaft oder die FindFoldersResults.TotalCount-Eigenschaft |
Das TotalItemsInView-Attribut auf dem RootFolder(FindItemResponseMessage)-Element oder dem RootFolder(FindFolderResponseMessage)-Element |
Offset des ersten Elements oder Ordners ist nicht in der aktuellen Antwort enthalten |
Die FindItemsResults.NextPageOffset-Eigenschaft oder die FindFoldersResults.NextPageOffset-Eigenschaft |
Das IndexedPagingOffset-Attribut auf dem RootFolder-Element |
Indikator, dass die Antwort das letzte Element oder den letzten Ordner in der Liste enthält |
Die FindItemsResults.MoreAvailable-Eigenschaft oder die FindFoldersResults.MoreAvailable-Eigenschaft |
Das IncludesLastItemInRange-Attribut auf dem RootFolder-Element |
Funktionsweise des Pagings
Um zu verstehen, wie das Paging funktioniert, ist es hilfreich die Nachrichten in einem Ordner als nebeneinander angeordnete Billboards in einem Feld außerhalb Ihres Hauses zu visualisieren. Sie können einige dieser Billboards durch ein magisches Fenster sehen. Sie können die Größe des Fensters ändern (um eine größere oder kleinere Anzahl der Billboards zu sehen) und Sie können das Fenster verlagern (um zu steuern, welche Billboards Sie sehen und welche nicht). Diese Manipulation des Fensters ist das Paging.
Wenn Sie Ihre Anforderung an den Exchange-Server senden, spezifizieren Sie die Größe Ihres Fensters im Hinblick auf die Zahl der Elemente, die zurückgesendet werden sollen. Sie bestimmen die Position des Fensters, indem Sie einen Ausgangspunkt bestimmen (entweder den Anfang der Zeile oder das Ende der Zeile) und ein Offset von diesem Ausgangspunkt, der in einer Nummer von Elementen angegeben wird. Der Anfang des Fensters ist die Nummer der Elemente, die durch den Offset vom Ausgangspunkt bestimmt wurden.
Das Paging fängt an ein bisschen spannender zu sein, wenn es um die Antwort des Servers geht, und darum, wie Ihre Anwendung diese Antwort verwenden kann, um ihre nächste Anforderung zu gestalten. Der Server stellt Ihnen drei Informationen bereit, die Sie dazu verwenden können, um zu bestimmen, wie Ihr „Fenster“ für Ihre nächste Anforderung konfiguriert werden soll:
Ob die Ergebnisse in der Antwort das letzte Element in der Gesamtergebnismenge auf dem Server enthalten.
Die Gesamtzahl der Elemente im Resultset auf dem Server.
Was der nächste Offsetwert sein sollte, wenn Sie das Fenster zum nächsten Element im Resultset bringen möchten, das in der aktuellen Antwort nicht enthalten ist.
Betrachten wir ein einfaches Beispiel. Stellen Sie sich einen Posteingang mit 15 Nachrichten vor. Ihre Anwendung sendet eine anfängliche Anforderung, um maximal 10 Elemente abzurufen, beginnend am Anfang der Liste der Nachrichten (sodass der Offset gleich Null ist). Der Server antwortet mit den ersten 10 Nachrichten und gibt an, dass die Antwort das letzte Element nicht beinhaltet, dass insgesamt 15 Elemente vorhanden sind, und dass der nächste Offset 10 sein sollte.
Abbildung 1: Anfordern von 10 Elementen am Offset 0 vom Anfang einer Liste mit 15 Elementen
Ihre Anwendung sendet dann erneut die gleichen Anforderungen an den Server, wobei die einzige Änderung darin besteht, dass der Offset jetzt 10 gleicht. Der Server gibt die letzten fünf Elemente zurück und gibt an, dass die Antwort nicht das letzte Elemente enthält, dass insgesamt 15 Elemente vorhanden sind, und dass der nächste Offset 15 sein sollte (obwohl Sie natürlich das Ende erreich haben und demnach kein weiterer Offset folgen wird.)
Abbildung 2: Anfordern von 10 Elementen bei Offset 10 vom Anfang einer Liste mit 15 Elementen
Entwurfsaspekte für das Paging
Um das Paging in Ihrer Anwendung optimal zu nutzen, müssen Sie sich einige Aspekte gründlich überlegen. Beispielsweise, wie groß wollen Sie Ihr „Fenster“ machen? Was machen Sie, wenn sich die Ergebnisse auf dem Server ändern, während Sie das „Fenster“ verschieben?
Die Größe des Fensters bestimmen
Es gibt keine „universale“ maximale Eintragnummer, die alle Anwendungen verwenden sollten. Das Bestimmen der für Ihre Anwendung geeigneten Nummer hängt von mehreren Faktoren ab. Es empfiehlt sich allerdings die folgenden Richtlinien im Kopf zu behalten:
Standardmäßig beschränkt Exchange die maximale Anzahl von Elementen, die in einer einzigen Anforderung zurückgegeben werden können auf 1000.
Wenn Sie die maximale Anzahl von Einträgen auf eine größere Zahl festlegen, müssen Sie weniger Anforderungen senden, um alle Elemente zu erhalten, Sie werden jedoch länger auf Antworten warten müssen.
Wenn Sie die maximale Anzahl von Einträgen auf eine kleinere Zahl festlegen, wird die Antwortzeit beschleunigt, Sie werden mehrere Anforderungen senden müssen, um alle Elemente zu erhalten.
Behandeln von Änderungen zum Resultset
In dem bereits im Artikel erwähnten vereinfachten Beispiel war die Anzahl der Elemente im Posteingang des Benutzers konstant. In Wirklichkeit kann sich die Anzahl der Elemente in einem Posteingang jedoch häufig ändern. Nue Nachrichten können eintreffen und Elemente können jederzeit gelöscht und verschoben werden. Doch wie wirkt sich dies auf das Paging aus? Zur Veranschaulichung werden wir nun das frühere Beispielszenario ein wenig ändern.
Wir beginnen wieder mit den 15 Elementen im Posteingang des Benutzers und senden die selbe Anfangsanforderung. Wie bereits zuvor antwortet der Server mit den ersten 10 Nachrichten und gibt an, dass die Antwort das letzte Element nicht beinhaltet, dass insgesamt 15 Elemente vorhanden sind, und dass der nächste Offset 10 sein sollte, wie veranschaulicht auf der Abbildung 1.
Während Ihre Anwendung diese 10 Elemente verarbeitet, trifft einer neue Nachricht in Ihrem Posteingang ein und wird zum Resultset auf dem Server hinzugefügt. Ihre Anwendung sendet die gleiche Anforderung an den Server weiter (nur bei dem auf 10 eingestellten Offset). Diesmal bekommt der Server sechs Elemente zurück und gibt an, dass das Resultset insgesamt 16 Elemente enthält.
In diesem Moment fragen Sie sich vielleicht, ob dies überhaupt ein Problem darstellt. Schließlich haben sie 16 Elemente zu den zwei Antworten zurückbekommen. Warum dann die ganze Aufregung? Die Antwort darauf häng davon ab, wohin in der Liste das neue Element platziert wurde. Wenn die Liste so sortiert ist, dass die ältesten Elemente (nach Empfangsdatum/Zeit) erst stehen, haben Sie keinen Grund zur Beunruhigung. Das neue Element wird an das Ende der Liste gestellt und wird in die nächsten Antwort einbezogen.
Abbildung 3: Anfordern von 10 Elementen bei Offset 10 vom Anfang einer Liste mit 16 Elementen, wobei das 16. Element in der Liste neu ist
Falls die Liste so sortiert ist, dass die neuesten Elemente erst stehen, ist dies ein Problem. In diesem Fall wäre das erste Element in der zweiten Anforderung das letzte Element der vorherigen Anforderung plus die restlichen fünf Elemente aus der ursprünglichen 15. Um es an unserem magischen Fenster zu veranschaulichen, Sie haben Ihr Fenster um 10 verschoben, aber die Billboards selbst sind ebenfalls um 1 verschoben worden.
Abbildung 4: Anfordern von 10 Elementen bei Offset 10 vom Anfang einer Liste mit 16 Elementen, wobei das erste Element in der Liste neu ist
Eine Möglichkeit, wie eine Änderung der Ergebnisse auf dem Server erkannt werden kann, ist das Verwenden des Konzeptes eines Ankerelements. Ein Ankerelement ist ein zusätzliches Element in Ihrer Antwort, dass nicht mit den anderen Ergebnisse mitverarbeitet wird, aber zum Vergleichen mit den nächsten Ergebnissen verwendet wird, um festzustellen, ob die Elemente selbst verschoben wurden. Um es wieder mittels unseres Beispiels zu veranschaulichen, wenn Ihre Anwendung eine „Fenster“-Größe von 10 verwendet, stellen Sie in Wirklichkeit die maximale Anzahl von Elementen, die zurückgesetzt werden, auf 11. Ihre Anwendung verarbeitet die ersten 10 Elemente in der Antwort wie gewohnt. Für das letzte Element speichern Sie den Bezeichner des Elements als Anker und geben Sie die nächste Anforderung mit einem Offset von 10 ein. Wenn sich die Daten nicht geändert haben, sollte das erste Element in der zweiten Antwort einen Bezeichner haben, der mit dem Anker übereinstimmt. Wenn die Elementbezeichner nicht übereinstimmen, wissen Sie, dass die Daten in den Abschnitten der Liste, die Sie bereits „ausgelagert“ haben, entfernt oder eingefügt wurden.
Auch wenn Sie wissen, das sich die Daten geändert haben, müssen Sie sich immer noch entscheiden, wie reagiert werden soll. Auch auf diese Frage gibt es keine universale Antwort. Ihre Aktionen werden von der Art Ihrer Anwendung und davon, wie wichtig es ist, alle Elemente zu erfassen, abhängen. Sie könnten sie völlig ignorieren, den Vorgang neu starten, oder zurückverfolgen und versuchen, die Stelle der Änderung zu finden.
Beispiel: Eine ausgelagerte Suche mittels verwalteten EWS-API durchführen
Das Paging wird von den folgenden verwalteten EWS-API-Methoden unterstützt:
Wenn Sie die verwaltete EWS-API verwenden, konfiguriert Ihre Anwendung das Paging mit der ItemView oder FolderView-Klasse und empfängt Informationen von dem Server bezüglich des Pagings von der FindItemsResults oder der FindFoldersResults-Klasse.
Im folgenden Beispiel werden alle Elemente in einem Ordner mithilfe einer ausgelagerten Suche abgerufen, die fünf Elemente in jeder Antwort zurückgibt. Außerdem ruft es ein zusätzliches Element ab, das als Anker dient, um Änderungen an den Ergebnissen auf dem Server zu erkennen.
In diesem Beispiel wird davon ausgegangen, dass das ExchangeService-Objekt mit gültigen Werten in den Credentials- und Url-Eigenschaften initialisiert wurde.
using Microsoft.Exchange.WebServices.Data;
static void PageSearchItems(ExchangeService service, WellKnownFolderName folder)
{
int pageSize = 5;
int offset = 0;
// Request one more item than your actual pageSize.
// This will be used to detect a change to the result
// set while paging.
ItemView view = new ItemView(pageSize + 1, offset);
view.PropertySet = new PropertySet(ItemSchema.Subject);
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
view.Traversal = ItemTraversal.Shallow;
bool moreItems = true;
ItemId anchorId = null;
while (moreItems)
{
try
{
FindItemsResults<Item> results = service.FindItems(folder, view);
moreItems = results.MoreAvailable;
if (moreItems && anchorId != null)
{
// Check the first result to make sure it matches
// the last result (anchor) from the previous page.
// If it doesn't, that means that something was added
// or deleted since you started the search.
if (results.Items.First<Item>().Id != anchorId)
{
Console.WriteLine("The collection has changed while paging. Some results may be missed.");
}
}
if (moreItems)
view.Offset += pageSize;
anchorId = results.Items.Last<Item>().Id;
// Because you're including an additional item on the end of your results
// as an anchor, you don't want to display it.
// Set the number to loop as the smaller value between
// the number of items in the collection and the page size.
int displayCount = 0;
if ((results.MoreAvailable == false && results.Items.Count > pageSize) || (results.Items.Count < pageSize))
{
displayCount = results.Items.Count;
}
else
{
displayCount = pageSize;
}
for (int i = 0; i < displayCount; i++)
{
Item item = results.Items[i];
Console.WriteLine("Subject: {0}", item.Subject);
Console.WriteLine("Id: {0}\n", item.Id.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine("Exception while paging results: {0}", ex.Message);
}
}
}
Beispiel: Eine ausgelagerte Suche mittels EWS durchführen
Das Paging wird von den folgenden EWS-Vorgängen unterstützt:
Wenn Sie EWS verwenden, konfiguriert ihre Anwendung das Paging mit den IndexedPageItemView-Element oder dem IndexedPageFolderView-Element und empfängt Informationen vom Server hinsichtlich des Pagings aus dem RootFolder (FindItemResponseMessage)-Element oder dem RootFolder (FindFolderResponseMessage)-Element.
In diesem Anforderungsbeispiel wird eine FindItem-Anforderung für maximal sechs Elemente gesendet, beginnend bei einem Offset von 0 vom Anfang der Liste der Elemente im Posteingang des Benutzers.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2007_SP1" />
<t:TimeZoneContext>
<t:TimeZoneDefinition Id="Eastern Standard Time" />
</t:TimeZoneContext>
</soap:Header>
<soap:Body>
<m:FindItem Traversal="Shallow">
<m:ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
<t:AdditionalProperties>
<t:FieldURI FieldURI="item:Subject" />
</t:AdditionalProperties>
</m:ItemShape>
<m:IndexedPageItemView MaxEntriesReturned="6" Offset="0" BasePoint="Beginning" />
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="inbox" />
</m:ParentFolderIds>
</m:FindItem>
</soap:Body>
</soap:Envelope>
Der Servers gibt die folgende Antwort zurück, die sechs Elemente enthält. Die Antwort gibt außerdem an, dass in den Ergebnissen auf dem Server insgesamt acht Elemente vorhanden sind, und dass das letzte Element in der Ergebnisliste nicht in der Antwort enthalten ist.
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="775" MinorBuildNumber="35" Version="V2_4"
xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder IndexedPagingOffset="6" TotalItemsInView="8" IncludesLastItemInRange="false">
<t:Items>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>Query</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>Update</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>Planning resources</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>Timeline</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>For your perusal</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>meeting notes</t:Subject>
</t:Message>
</t:Items>
</m:RootFolder>
</m:FindItemResponseMessage>
</m:ResponseMessages>
</m:FindItemResponse>
</s:Body>
</s:Envelope>
In diesem Beispiel wird die gleiche Anforderung gesendet, aber diesmal wird das Offset-Attribut in „fünf“ geändert, wodurch angegeben wird, dass der Server höchstens sechs Elemente zurückgeben sollte, beginnend mit dem Offset von fünf vom Anfang.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<t:RequestServerVersion Version="Exchange2007_SP1" />
<t:TimeZoneContext>
<t:TimeZoneDefinition Id="Eastern Standard Time" />
</t:TimeZoneContext>
</soap:Header>
<soap:Body>
<m:FindItem Traversal="Shallow">
<m:ItemShape>
<t:BaseShape>IdOnly</t:BaseShape>
<t:AdditionalProperties>
<t:FieldURI FieldURI="item:Subject" />
</t:AdditionalProperties>
</m:ItemShape>
<m:IndexedPageItemView MaxEntriesReturned="6" Offset="5" BasePoint="Beginning" />
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="inbox" />
</m:ParentFolderIds>
</m:FindItem>
</soap:Body>
</soap:Envelope>
Der Servers sendet die folgende Antwort, die drei Elemente enthält. Die Antwort gibt außerdem an, dass in den Ergebnissen auf dem Server immer noch insgesamt acht Elemente vorhanden sind, und dass das letzte Element in der Ergebnisliste nicht in der Antwort einbezogen ist.
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="775" MinorBuildNumber="35" Version="V2_4"
xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:FindItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:RootFolder IndexedPagingOffset="8" TotalItemsInView="8" IncludesLastItemInRange="true">
<t:Items>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>meeting notes</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>Meeting notes</t:Subject>
</t:Message>
<t:Message>
<t:ItemId Id="AAMkAGM2..." ChangeKey="CQAAABYA..." />
<t:Subject>This cat is hilarious!</t:Subject>
</t:Message>
</t:Items>
</m:RootFolder>
</m:FindItemResponseMessage>
</m:ResponseMessages>
</m:FindItemResponse>
</s:Body>
</s:Envelope>