Erstellen eines OData v3-Endpunkts mit Web-API 2
von Mike Wasson
Abgeschlossenes Projekt herunterladen
Das Open Data Protocol (OData) ist ein Datenzugriffsprotokoll für das Web. OData bietet eine einheitliche Möglichkeit, Daten zu strukturieren, die Daten abzufragen und das Dataset über CRUD-Vorgänge (Erstellen, Lesen, Aktualisieren und Löschen) zu bearbeiten. OData unterstützt sowohl AtomPub (XML) als auch JSON-Formate. OData definiert auch eine Möglichkeit, Metadaten zu den Daten verfügbar zu machen. Clients können die Metadaten verwenden, um die Typinformationen und Beziehungen für das Dataset zu ermitteln.
ASP.NET-Web-API erleichtert das Erstellen eines OData-Endpunkts für ein Dataset. Sie können genau steuern, welche OData-Vorgänge der Endpunkt unterstützt. Sie können mehrere OData-Endpunkte zusammen mit Nicht-OData-Endpunkten hosten. Sie haben die volle Kontrolle über Ihr Datenmodell, Ihre Back-End-Geschäftslogik und Die Datenebene.
Im Tutorial verwendete Softwareversionen
- Visual Studio 2013
- Web-API 2
- OData Version 3
- Entity Framework 6
- Fiddler-Webdebuggenproxy (optional)
Die OData-Unterstützung der Web-API wurde in ASP.NET and Web Tools Update 2012.2 hinzugefügt. In diesem Tutorial werden jedoch Gerüste verwendet, die in Visual Studio 2013 hinzugefügt wurden.
In diesem Tutorial erstellen Sie einen einfachen OData-Endpunkt, den Clients abfragen können. Außerdem erstellen Sie einen C#-Client für den Endpunkt. Nachdem Sie dieses Tutorial abgeschlossen haben, zeigen die nächsten Tutorials, wie Sie weitere Funktionen hinzufügen, einschließlich Entitätsbeziehungen, Aktionen und $expand/$select.
- Erstellen des Visual Studio-Projekts
- Hinzufügen eines Entitätsmodells
- Hinzufügen eines OData-Controllers
- Hinzufügen von EDM und Route
- Seeding der Datenbank (optional)
- Erkunden des OData-Endpunkts
- OData-Serialisierungsformate
Erstellen des Visual Studio-Projekts
In diesem Tutorial erstellen Sie einen OData-Endpunkt, der grundlegende CRUD-Vorgänge unterstützt. Der Endpunkt macht eine einzelne Ressource verfügbar, eine Liste von Produkten. In späteren Tutorials werden weitere Features hinzugefügt.
Starten Sie Visual Studio, und wählen Sie Neues Projekt auf der Startseite aus. Oder wählen Sie im Menü Datei die Option Neu und dann Projekt aus.
Wählen Sie im Bereich Vorlagendie Option Installierte Vorlagen aus, und erweitern Sie den Knoten Visual C#. Wählen Sie unter Visual C#die Option Web aus. Wählen Sie die Vorlage ASP.NET Webanwendung aus.
Wählen Sie im Dialogfeld Neues ASP.NET Projekt die Vorlage Leer aus. Aktivieren Sie unter "Ordner und Kernverweise hinzufügen für..." die Option Web-API. Klicken Sie auf OK.
Hinzufügen eines Entitätsmodells
Ein Modell ist ein Objekt, das für die Daten in Ihrer Anwendung steht. Für dieses Tutorial benötigen wir ein Modell, das ein Produkt darstellt. Das Modell entspricht unserem OData-Entitätstyp.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner „Modelle“. Wählen Sie im Kontextmenü die Option Hinzufügen und dann Klasse.
Geben Sie der Klasse im Dialogfeld Neues Element hinzufügen den Namen "Product".
Hinweis
Gemäß der Konvention werden Modellklassen im Ordner Models platziert. Sie müssen diese Konvention nicht in Ihren eigenen Projekten befolgen, aber wir verwenden sie für dieses Tutorial.
Fügen Sie in der Datei Product.cs die folgende Klassendefinition hinzu:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
Die ID-Eigenschaft ist der Entitätsschlüssel. Clients können Produkte nach ID abfragen. Dieses Feld wäre auch der Primärschlüssel in der Back-End-Datenbank.
Erstellen Sie das Projekt jetzt. Im nächsten Schritt verwenden wir einige Visual Studio-Gerüste, die reflektion verwenden, um den Produkttyp zu finden.
Hinzufügen eines OData-Controllers
Ein Controller ist eine Klasse, die HTTP-Anforderungen verarbeitet. Sie definieren einen separaten Controller für jede Entitätsmenge in Dem OData-Dienst. In diesem Tutorial erstellen wir einen einzelnen Controller.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner „Controller“. Wählen Sie Hinzufügen und dann Controller.
Wählen Sie im Dialogfeld Gerüst hinzufügen die Option "Web API 2 OData Controller with actions, using Entity Framework" aus.
Geben Sie dem Controller im Dialogfeld Controller hinzufügen den Namen "ProductsController". Aktivieren Sie das Kontrollkästchen "Asynchrone Controlleraktionen verwenden". Wählen Sie in der Dropdownliste Modell die Klasse Product aus.
Klicken Sie auf die Schaltfläche Neuer Datenkontext... . Behalten Sie den Standardnamen für den Datentyp bei, und klicken Sie auf Hinzufügen.
Klicken Sie im Dialogfeld Controller hinzufügen auf Hinzufügen, um den Controller hinzuzufügen.
Hinweis: Wenn Sie die Fehlermeldung "Fehler beim Abrufen des Typs..." erhalten, stellen Sie sicher, dass Sie das Visual Studio-Projekt erstellt haben, nachdem Sie die Product-Klasse hinzugefügt haben. Das Gerüst verwendet Reflektion, um die -Klasse zu finden.
Das Gerüst fügt dem Projekt zwei Codedateien hinzu:
- Products.cs definiert den Web-API-Controller, der den OData-Endpunkt implementiert.
- ProductServiceContext.cs stellt Methoden zum Abfragen der zugrunde liegenden Datenbank mithilfe von Entity Framework bereit.
Hinzufügen von EDM und Route
Erweitern Sie in Projektmappen-Explorer den Ordner App_Start, und öffnen Sie die Datei mit dem Namen WebApiConfig.cs. Diese Klasse enthält Konfigurationscode für die Web-API. Ersetzen Sie diesen Code durch Folgendes:
using ProductService.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;
namespace ProductService
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
}
}
}
Mit diesem Code werden zwei Dinge ausgeführt:
- Erstellt ein Entity Data Model (EDM) für den OData-Endpunkt.
- Fügt eine Route für den Endpunkt hinzu.
Ein EDM ist ein abstraktes Modell der Daten. Das EDM wird verwendet, um das Metadatendokument zu erstellen und die URIs für den Dienst zu definieren. Der ODataConventionModelBuilder erstellt einen EDM mithilfe einer Reihe von Standardbenennungskonventionen EDM. Dieser Ansatz erfordert den geringsten Code. Wenn Sie mehr Kontrolle über den EDM wünschen, können Sie die ODataModelBuilder-Klasse verwenden, um die EDM zu erstellen, indem Sie Eigenschaften, Schlüssel und Navigationseigenschaften explizit hinzufügen.
Die EntitySet-Methode fügt dem EDM einen Entitätssatz hinzu:
modelBuilder.EntitySet<Product>("Products");
Die Zeichenfolge "Products" definiert den Namen des Entitätssatzes. Der Name des Controllers muss mit dem Namen des Entitätssatzes übereinstimmen. In diesem Tutorial hat der Entitätssatz den Namen "Products" und der Controller den Namen ProductsController
. Wenn Sie den Entitätssatz "ProductSet" nennen, würden Sie dem Controller ProductSetController
den Namen geben. Beachten Sie, dass ein Endpunkt mehrere Entitätssätze aufweisen kann. Rufen Sie EntitySet<T> für jede Entitätsmenge auf, und definieren Sie dann einen entsprechenden Controller.
Die MapODataRoute-Methode fügt eine Route für den OData-Endpunkt hinzu.
config.Routes.MapODataRoute("ODataRoute", "odata", model);
Der erste Parameter ist ein Anzeigename für die Route. Für Clients Ihres Diensts wird dieser Name nicht angezeigt. Der zweite Parameter ist das URI-Präfix für den Endpunkt. Bei diesem Code lautet der URI für den Entitätssatz Products http:// hostname/odata/Products. Ihre Anwendung kann über mehrere OData-Endpunkte verfügen. Rufen Sie für jeden Endpunkt MapODataRoute auf, und geben Sie einen eindeutigen Routennamen und ein eindeutiges URI-Präfix an.
Seeding der Datenbank (optional)
In diesem Schritt verwenden Sie Entity Framework, um die Datenbank mit einigen Testdaten zu seeden. Dieser Schritt ist optional, aber Sie können Ihren OData-Endpunkt sofort testen.
Wählen Sie im Menü Extras die Option NuGet-Paket-Manager und dann Paket-Manager-Konsole aus. Geben Sie im Fenster Paket-Manager-Konsole den folgenden Befehl ein:
Enable-Migrations
Dadurch werden ein Ordner namens Migrations und eine Codedatei namens Configuration.cs hinzugefügt.
Öffnen Sie diese Datei, und fügen Sie der -Methode den Configuration.Seed
folgenden Code hinzu.
protected override void Seed(ProductService.Models.ProductServiceContext context)
{
// New code
context.Products.AddOrUpdate(new Product[] {
new Product() { ID = 1, Name = "Hat", Price = 15, Category = "Apparel" },
new Product() { ID = 2, Name = "Socks", Price = 5, Category = "Apparel" },
new Product() { ID = 3, Name = "Scarf", Price = 12, Category = "Apparel" },
new Product() { ID = 4, Name = "Yo-yo", Price = 4.95M, Category = "Toys" },
new Product() { ID = 5, Name = "Puzzle", Price = 8, Category = "Toys" },
});
}
Geben Sie im Paket-Manager-Konsolenfenster die folgenden Befehle ein:
Add-Migration Initial
Update-Database
Diese Befehle generieren Code, der die Datenbank erstellt, und führen dann diesen Code aus.
Erkunden des OData-Endpunkts
In diesem Abschnitt verwenden wir den Fiddler-Webdebuggenproxy , um Anforderungen an den Endpunkt zu senden und die Antwortnachrichten zu untersuchen. Dies hilft Ihnen, die Funktionen eines OData-Endpunkts zu verstehen.
Drücken Sie in Visual Studio F5, um das Debuggen zu starten. Standardmäßig öffnet Visual Studio Ihren Browser mit http://localhost:*port*
, wobei Port die in den Projekteinstellungen konfigurierte Portnummer ist.
Sie können die Portnummer in den Projekteinstellungen ändern. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie Eigenschaften aus. Wählen Sie im Eigenschaftenfenster Web aus. Geben Sie die Portnummer unter Projekt-URL ein.
Dienstdokument
Das Dienstdokument enthält eine Liste der Entitätssätze für den OData-Endpunkt. Um das Dienstdokument abzurufen, senden Sie eine GET-Anforderung an den Stamm-URI des Diensts.
Geben Sie bei Fiddler den folgenden URI auf der Registerkarte Composer ein: http://localhost:port/odata/
, wobei Port die Portnummer ist.
Klicken Sie auf die Schaltfläche Ausführen . Fiddler sendet eine HTTP GET-Anforderung an Ihre Anwendung. Die Antwort sollte in der Liste Websitzungen angezeigt werden. Wenn alles funktioniert, ist der status Code 200.
Doppelklicken Sie in der Liste Websitzungen auf die Antwort, um die Details der Antwortnachricht auf der Registerkarte Inspektoren anzuzeigen.
Die unformatierte HTTP-Antwortnachricht sollte in etwa wie folgt aussehen:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/atomsvc+xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 17:51:01 GMT
Content-Length: 364
<?xml version="1.0" encoding="utf-8"?>
<service xml:base="http://localhost:60868/odata"
xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
<workspace>
<atom:title type="text">Default</atom:title>
<collection href="Products">
<atom:title type="text">Products</atom:title>
</collection>
</workspace>
</service></pre>
Standardmäßig gibt die Web-API das Dienstdokument im AtomPub-Format zurück. Um JSON anzufordern, fügen Sie der HTTP-Anforderung den folgenden Header hinzu:
Accept: application/json
Die HTTP-Antwort enthält nun eine JSON-Nutzlast:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 22:59:28 GMT
Content-Length: 136
{
"odata.metadata":"http://localhost:60868/odata/$metadata","value":[
{
"name":"Products","url":"Products"
}
]
}
Dienstmetadatendokument
Das Dienstmetadatendokument beschreibt das Datenmodell des Diensts unter Verwendung einer XML-Sprache, die als Konzeptionelle Schemadefinitionssprache (Conceptual Schema Definition Language, CSDL) bezeichnet wird. Das Metadatendokument zeigt die Struktur der Daten im Dienst und kann zum Generieren von Clientcode verwendet werden.
Um das Metadatendokument abzurufen, senden Sie eine GET-Anforderung an http://localhost:port/odata/$metadata
. Hier sehen Sie die Metadaten für den Endpunkt, die in diesem Tutorial gezeigt werden.
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:05:52 GMT
Content-Length: 1086
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<Schema Namespace="ProductService.Models" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
<EntityType Name="Product">
<Key>
<PropertyRef Name="ID" />
</Key>
<Property Name="ID" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" />
<Property Name="Price" Type="Edm.Decimal" Nullable="false" />
<Property Name="Category" Type="Edm.String" />
</EntityType>
</Schema>
<Schema Namespace="Default" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
<EntityContainer Name="Container" m:IsDefaultEntityContainer="true">
<EntitySet Name="Products" EntityType="ProductService.Models.Product" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Entitätenmenge
Um den Entitätssatz Products abzurufen, senden Sie eine GET-Anforderung an http://localhost:port/odata/Products
.
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:01:31 GMT
Content-Length: 459
{
"odata.metadata":"http://localhost:60868/odata/$metadata#Products","value":[
{
"ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
},{
"ID":2,"Name":"Socks","Price":"5.00","Category":"Apparel"
},{
"ID":3,"Name":"Scarf","Price":"12.00","Category":"Apparel"
},{
"ID":4,"Name":"Yo-yo","Price":"4.95","Category":"Toys"
},{
"ID":5,"Name":"Puzzle","Price":"8.00","Category":"Toys"
}
]
}
Entität
Um ein einzelnes Produkt zu erhalten, senden Sie eine GET-Anforderung an http://localhost:port/odata/Products(1)
, wobei "1" die Produkt-ID ist.
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:04:29 GMT
Content-Length: 140
{
"odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element","ID":1,
"Name":"Hat","Price":"15.00","Category":"Apparel"
}
OData-Serialisierungsformate
OData unterstützt mehrere Serialisierungsformate:
- Atom Pub (XML)
- JSON "light" (eingeführt in OData v3)
- JSON "ausführlich" (OData v2)
Standardmäßig verwendet die Web-API das AtomPubJSON-Format "light".
Legen Sie zum Abrufen des AtomPub-Formats den Accept-Header auf "application/atom+xml" fest. Hier ist ein Beispiel-Antworttext:
<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://localhost:60868/odata" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
<id>http://localhost:60868/odata/Products(1)</id>
<category term="ProductService.Models.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="http://localhost:60868/odata/Products(1)" />
<link rel="self" href="http://localhost:60868/odata/Products(1)" />
<title />
<updated>2013-09-23T23:42:11Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:ID m:type="Edm.Int32">1</d:ID>
<d:Name>Hat</d:Name>
<d:Price m:type="Edm.Decimal">15.00</d:Price>
<d:Category>Apparel</d:Category>
</m:properties>
</content>
</entry>
Sie sehen einen offensichtlichen Nachteil des Atom-Formats: Es ist viel ausführlicher als das JSON-Licht. Wenn Sie jedoch über einen Client verfügen, der AtomPub versteht, kann der Client dieses Format vor JSON bevorzugen.
Dies ist die JSON-Light-Version derselben Entität:
{
"odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element",
"ID":1,
"Name":"Hat",
"Price":"15.00",
"Category":"Apparel"
}
Das JSON-Lichtformat wurde in Version 3 des OData-Protokolls eingeführt. Aus Gründen der Abwärtskompatibilität kann ein Client das ältere JSON-Format "ausführlich" anfordern. Um ausführliche JSON-Dateien anzufordern, legen Sie den Accept-Header auf fest application/json;odata=verbose
. Hier ist die ausführliche Version:
{
"d":{
"__metadata":{
"id":"http://localhost:18285/odata/Products(1)",
"uri":"http://localhost:18285/odata/Products(1)",
"type":"ProductService.Models.Product"
},"ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
}
}
Dieses Format vermittelt mehr Metadaten im Antworttext, was zu einem erheblichen Mehraufwand für eine gesamte Sitzung führen kann. Außerdem wird eine Dereferenzierungsebene hinzugefügt, indem das Objekt in eine Eigenschaft namens "d" umschlossen wird.