ASP.NET Web Api 2 und Odata 4

Wie die Headline schon vermuten lässt: ganz schön kompliziert. Dennoch löst Odata eine Reihe von Problemen im REST Web Service-Umfeld. Der Open Data Standard stammt aus der Feder von Microsoft und erlaubt es auf einen Service verschiedene Abfragen durchzuführen. Anders als im “klassischen” REST-Ansatz sind damit eine Vielzahl variabler Querys möglich. Um eine Entität per Rest abzufragen, folgt man in der Regel url/servicemethode/id. Mit Odata sieht die gleiche Abfrage so aus url/servicemethode[id]. Im ersten Fall muss allerdings eine spezielle Route und eine Methodenüberladung mit einem Parameter angelegt werden.

Odata ist sehr hilfreich in Sorting, Querying und Paging-Szenarien, insofern lohnt sich ein Blick darauf. Leider hat Microsoft die Odata Implementierung im ASP.NET Web API Framework mehrfach und grundlegend geändert. So findet man in den Suchmaschinen meist Code, der nicht funktioniert. Auch von mir stammt ein derartiger Blogartikel. Weitgehend korrekt, aber in manchen Details nicht mehr aktuell.

Die Basis des Web API Services ist der Service Controller, der die notwendigen CRUD Operationen bereit stellt. In VB.NET werden diese Methoden mit den Präfixen Get usw in Kombination mit dem Controllernamen benannt. Dies ist die Konvention. Mit dem neuen Attribut Routing kann man in der Namensgebung auch kreativer sein. Sollte man aber ohne Not nicht.

Ganz wesentlich: ein API Controller und ein Odata Controller sind zwei getrennte Welten, sprich Klassen. Die eine erbt vom API Controller, die andere vom Odata Controller.

Bevor man sich lange abmüht, empfehle ich per Scaffolding (Gerüstelement) den Odata Controller anzulegen.

image

Dabei wird eine vorhandene Modelklasse ausgewählt. In diesem Projekt wurde diese per Entity Framework aus der Northwind Datenbank generiert.

image

Falls dies ein jungfräuliches Web-Projekt ist, wird keine Datenkontextklasse vorhanden sein. Lassen Sie sich diese bequem generieren, indem sie auf das + klicken.

Die Controllerklasse enthält dann u.a. folgenden .NET Code

   1:   Public Class CustomersOController
   2:          Inherits ODataController
   3:   
   4:          Private db As New NorthwindEntities
   5:   
   6:          ' GET: odata/CustomersO
   7:          <EnableQuery>
   8:          Function GetCustomersO() As IQueryable(Of Customers)
   9:              Return db.Customers
  10:          End Function

 

Um den Controller per HTTP auch aufrufen zu können, muss eine Route konfiguriert werden. In den guten alten WCF-Zeiten hätte man das in eine Config Datei geschrieben. Heute werden Konfigurationen in Code getippt. Im globa.asax Startup Event wird eine Methode RegisterRoutes aufgerufen, die auf eine Klasse in RouteConfig.VB verweist.

Der Code ab Zeile 17 wurde von mir eingefügt. Wirklich intuitiv finde ich den Code nicht. Die Route lautet nun odata und es ist nur der Controller CustomersO eingebunden.

   1:  Public Module WebApiConfig
   2:      Public Sub Register(config As HttpConfiguration)
   3:          ' Web-API-Konfiguration und -Dienste
   4:          ' Web-API für die ausschließliche Verwendung von 
Trägertokenauthentifizierung konfigurieren.
   5:          config.SuppressDefaultHostAuthentication()
   6:          config.Filters.Add(New HostAuthenticationFilter
(OAuthDefaults.AuthenticationType))
   7:   
   8:          ' Web-API-Routen
   9:          config.MapHttpAttributeRoutes()
  10:   
  11:          config.Routes.MapHttpRoute(
  12:              name:="DefaultApi",
  13:              routeTemplate:="api/{controller}/{id}",
  14:              defaults:=New With {.id = RouteParameter.Optional}
  15:          )
  16:   
  17:          Dim builder As ODataModelBuilder = New ODataConventionModelBuilder()
  18:          builder.EntitySet(Of Customers)("CustomersO")
  19:          '       config.Routes.MapODataRoute("ODataRoute", Nothing, builder.GetEdmModel) Obsoloet
  20:   
  21:          config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel)
  22:          config.EnsureInitialized()
  23:      End Sub

 

Es gibt nun einen Pfad api/ und einen Odata/. Wenn man die ersten 5 Kunden abrufen will, schränkt man dies wie folgt in der URL ein http://localhost:1929/odata/CustomersO?$top=5. Als Ergebnis erhält man JSON Daten

{
  "odata.metadata":"http://localhost:1929/odata/$metadata#CustomersO","value":[
    {
      "CustomerID":"ppedv","CompanyName":"ppedv","ContactName":null,"ContactTitle":null,"Address":null,"City":null,"
Region":null,"PostalCode":null,"Country":null,"Phone":null,"Fax":null,"LastChange":"AAAAAAAAz3M="
    },{

Kommentare sind geschlossen