Laden...

[gelöst] Web Api Paging -> Query Option inlinecount

Erstellt von t2t vor 7 Jahren Letzter Beitrag vor 7 Jahren 2.324 Views
T
t2t Themenstarter:in
415 Beiträge seit 2007
vor 7 Jahren
[gelöst] Web Api Paging -> Query Option inlinecount

Hallo zusammen,

ich versuche seit einiger Zeit vergeblich ein vernünftiges Paging mit der Web Api zum laufen zu bekommen. Folgendes Szenario:

Ich habe ein Website die per Ajax Call Datensätze von einer Web Api abruft. Dabei kommt mir sehr zu gute, dass ich die Query Optionen die man auch unter OData hat nutzen kann. Also beispielsweise $orderby, $skip und $top. Allerdings sehr großes Manko an dieser Sache ist, dass die überaus wichtige Option $inlinecount=allpages anscheinend nicht richtig unterstützt wird.

Daher kann ich auf der Website kein vernünftiges Paging umsetzen, wenn ich nicht weiß wie groß die Gesamtdatenmenge ist. Ich hab einige Blogartikel zu dem Thema gefunden, wo die Leute auf eine selbstgebastelte Lösung gesetzt haben. Finde ich aber sehr unschön, da ich in den meisten Fällen so die Möglichkeit verliere die Query Optionen zu verwenden. Und extra für sowas einen OData Endpunkt aufsetzen zu müssen, würde ich sehr gerne vermeiden wollen.

Daher meine Frage: Hat schon mal jemand erfolgreich einen Paging Ansatz umgesetzt? Muss ja irgendwie möglich sein. Wie sollen sonst die ganzen modernen Single-Page Webanwendungen sonst einen Web Api erfolgreich konsumieren?

T
t2t Themenstarter:in
415 Beiträge seit 2007
vor 7 Jahren

Okay, mit diesem Beispiel hat es nun doch geklappt. Unter Punkt "Server-Driven Paging" zweiter Absatz für non-OData formats.

16.834 Beiträge seit 2008
vor 7 Jahren

Hätte mich auch gewundert, dass das nicht funktioniert, denn quasi alle Resourcen-Systeme in Azure verwenden OData - und wir auch; auch Paging.
Die andere, sehr verbreite Variante ist, dass man via Header diese Informationen mitgibt.

X-Pagination-Total: 999999
X-Pagination-Limit: 500
X-Pagination-Offset: 99
X-Pagination-Returned: 123

Aber Du hast ja mittlerweile die Lösung.

T
t2t Themenstarter:in
415 Beiträge seit 2007
vor 7 Jahren

quasi alle Resourcen-Systeme in Azure verwenden OData

Genau das ist der springende Punkt. Sobald man einen ApiController und keinen ODataController verwendet, hat man nicht mehr die Möglichkeit per Query Option die Gesamtgröße der Datenmenge mitzubekommen.

Hier für die Nachwelt noch mal meine Lösung, da ich sie etwas von dem Beispiel abwandeln musste:

public async Task<IHttpActionResult> GetData<MyData> options /* ggf. weitere Parameter*/)
{
       var result = // Daten abrufen von UnitOfWork, DbContext, etc.

       int count = result.Count;

       IQueryable results = options.ApplyTo(result.AsQueryable());

       return Ok(new PageResult<MyData>(results as IEnumerable<MyData>, new Uri("next-page-uri"), count));
}
16.834 Beiträge seit 2008
vor 7 Jahren

Du missachtest dabei einen Punkt.
OData ist nicht einfach eine Json API, sondern ein Hypermedia-Protokoll.

Im Falle des API-Controllers gibst Du die Collections flach raus; Du hast hier also gar keine Protokollbeschreibung für Metadaten, wie den Count - und auch kein Platz dafür.
Das alles macht OData an dieser Stelle automatisch für Dich. Der Json-Return eines ODataControllers hat einen Content-Bereich (die Items) und Metadaten (und paar andere, wie Deeplinking etc).

Du musst also dieses Hypermedia-Protokoll selbst bauen oder andere nutzen (zB. Siren).
Das ist aber teil des API Designs, das man vor der Programmierung umsetzt, zB. in Form eines Swagger Contracts.

T
t2t Themenstarter:in
415 Beiträge seit 2007
vor 7 Jahren

OData ist nicht einfach eine Json API, sondern ein Hypermedia-Protokoll.

Das ist mir durchaus bewusst. Dennoch finde ich den Ansatz von MS eigentlich sehr smart mit einem einfachen ApiController gewisse OData Funktionalitäten zu bekommen, ohne extra einen vollwertigen OData Endpunkt aufsetzen zu müssen. Schade nur, dass eine so wichtige Funktionalität wie der inlinecount nicht unterstützt wird. Wäre ja eigentlich ein leichtes gewesen die Untersützung auch für diese einfache Json Api mitzuliefern. Aber gut, mit etwas eigenem Aufwand ist es ja auch zu lösen.

D
152 Beiträge seit 2013
vor 7 Jahren

Erhält man die Gesamtanzahl "@odata.count" eines EntitySet nicht mit $count=true ?
Wenn man die Gesamtanzahl kennt sollte doch auch ein clientseitiges Paging möglich sein

http://localhost/odata/Persons/?$count=true&$top=5&$skip=5


{
   "@odata.context": "http://localhost/odata/$metadata#Persons",
   "@odata.count": 10000,
   "value": [ {...}, {...}, {...}, {...}, {...}]
}

T
t2t Themenstarter:in
415 Beiträge seit 2007
vor 7 Jahren

Ja, ab V4 meine ich. V3 arbeitet noch mit inlinecount.