Erstellen eines OData v4-Endpunkts mit ASP.NET-Web-API
Das Open Data Protocol (OData) ist ein Datenzugriffsprotokoll für das Web. OData bietet eine einheitliche Möglichkeit zum Abfragen und Bearbeiten von Datasets über CRUD-Vorgänge (Erstellen, Lesen, Aktualisieren und Löschen).
ASP.NET-Web-API unterstützt sowohl v3 als auch v4 des Protokolls. Sie können sogar über einen v4-Endpunkt verfügen, der parallel zu einem v3-Endpunkt ausgeführt wird.
In diesem Tutorial wird gezeigt, wie Sie einen OData v4-Endpunkt erstellen, der CRUD-Vorgänge unterstützt.
Im Tutorial verwendete Softwareversionen
- Web-API 5.2
- OData v4
- Visual Studio 2017 (Herunterladen von Visual Studio 2017 hier)
- Entity Framework 6
- .NET 4.7.2
Tutorialversionen
Informationen zu OData Version 3 finden Sie unter Erstellen eines OData v3-Endpunkts.
Erstellen des Visual Studio-Projekts
Wählen Sie in Visual Studio im Menü Datei die Option Neues>Projekt aus.
Erweitern Sie Installiertes>Visual C#>Web, und wählen Sie die Vorlage ASP.NET Webanwendung (.NET Framework) aus. Nennen Sie das Projekt "ProductService".
Klicken Sie auf OK.
Wählen Sie die Vorlage Leer aus. Wählen Sie unter Ordner und Kernverweise hinzufügen für die Option Web-API aus. Klicken Sie auf OK.
Installieren der OData-Pakete
Wählen Sie im Menü Extras die Optionen NuGet-Paket-Manager>Paket-Manager-Konsole aus. Geben Sie im Fenster Paket-Manager-Konsole Folgendes ein:
Install-Package Microsoft.AspNet.Odata
Mit diesem Befehl werden die neuesten OData NuGet-Pakete installiert.
Hinzufügen einer Modellklasse
Ein Modell ist ein Objekt, das eine Datenentität in Ihrer Anwendung darstellt.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner „Modelle“. Wählen Sie im KontextmenüKlassehinzufügen> aus.
Hinweis
Gemäß der Konvention werden Modellklassen im Ordner Models platziert, aber Sie müssen diese Konvention nicht in Ihren eigenen Projekten befolgen.
Geben Sie der Klassen den Namen Product
. Ersetzen Sie in der Datei Product.cs den Boilerplate-Code durch Folgendes:
namespace ProductService.Models
{
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 Entitäten nach Schlüssel abfragen. Um beispielsweise das Produkt mit der ID 5 abzurufen, lautet /Products(5)
der URI . Die Id
Eigenschaft ist auch der Primärschlüssel in der Back-End-Datenbank.
Aktivieren von Entity Framework
In diesem Tutorial verwenden wir Entity Framework (EF) Code First, um die Back-End-Datenbank zu erstellen.
Hinweis
Für die Web-API OData ist EF nicht erforderlich. Verwenden Sie eine beliebige Datenzugriffsebene, die Datenbankentitäten in Modelle übersetzen kann.
Installieren Sie zunächst das NuGet-Paket für EF. Wählen Sie im Menü Extras die Optionen NuGet-Paket-Manager>Paket-Manager-Konsole aus. Geben Sie im Fenster Paket-Manager-Konsole Folgendes ein:
Install-Package EntityFramework
Öffnen Sie die datei Web.config, und fügen Sie den folgenden Abschnitt innerhalb des Konfigurationselements nach dem configSections-Element hinzu.
<configuration>
<configSections>
<!-- ... -->
</configSections>
<!-- Add this: -->
<connectionStrings>
<add name="ProductsContext" connectionString="Data Source=(localdb)\mssqllocaldb;
Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True;
AttachDbFilename=|DataDirectory|ProductsContext.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
Diese Einstellung fügt eine Verbindungszeichenfolge für eine LocalDB-Datenbank hinzu. Diese Datenbank wird verwendet, wenn Sie die App lokal ausführen.
Fügen Sie als Nächstes dem Ordner Models eine Klasse mit dem Namen ProductsContext
hinzu:
using System.Data.Entity;
namespace ProductService.Models
{
public class ProductsContext : DbContext
{
public ProductsContext()
: base("name=ProductsContext")
{
}
public DbSet<Product> Products { get; set; }
}
}
Gibt im Konstruktor "name=ProductsContext"
den Namen der Verbindungszeichenfolge an.
Konfigurieren des OData-Endpunkts
Öffnen Sie die Datei App_Start/WebApiConfig.cs. Fügen Sie die folgenden using-Anweisungen hinzu:
using ProductService.Models;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;
Fügen Sie dann der Register-Methode den folgenden Code hinzu:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: null,
model: builder.GetEdmModel());
}
}
Dieser Code erfüllt zwei Dinge:
- Erstellt ein Entitätsdatenmodell (Entity Data Model, EDM).
- Fügt eine Route hinzu.
Ein EDM ist ein abstraktes Modell der Daten. Das EDM wird verwendet, um das Dienstmetadatendokument zu erstellen. Die ODataConventionModelBuilder-Klasse erstellt ein EDM unter Verwendung von Standardbenennungskonventionen. Dieser Ansatz erfordert den geringsten Code. Wenn Sie mehr Kontrolle über das EDM wünschen, können Sie die ODataModelBuilder-Klasse verwenden, um das EDM zu erstellen, indem Sie Eigenschaften, Schlüssel und Navigationseigenschaften explizit hinzufügen.
Eine Route teilt der Web-API mit, wie HTTP-Anforderungen an den Endpunkt weitergeleitet werden. Um eine OData v4-Route zu erstellen, rufen Sie die MapODataServiceRoute-Erweiterungsmethode auf.
Wenn Ihre Anwendung über mehrere OData-Endpunkte verfügt, erstellen Sie eine separate Route für jeden. Geben Sie jeder Route einen eindeutigen Routennamen und ein präfix.
Hinzufügen des OData-Controllers
Ein Controller ist eine Klasse, die HTTP-Anforderungen verarbeitet. Sie erstellen einen separaten Controller für jede Entität in Ihrem OData-Dienst. In diesem Tutorial erstellen Sie einen Controller für die Product
Entität.
Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Controller, und wählen SieKlassehinzufügen> aus. Geben Sie der Klassen den Namen ProductsController
.
Hinweis
Die Version dieses Tutorials für OData v3 verwendet das Gerüst "Controller hinzufügen" . Derzeit gibt es kein Gerüst für OData v4.
Ersetzen Sie den Boilerplate-Code in ProductsController.cs durch Folgendes.
using ProductService.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
namespace ProductService.Controllers
{
public class ProductsController : ODataController
{
ProductsContext db = new ProductsContext();
private bool ProductExists(int key)
{
return db.Products.Any(p => p.Id == key);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
Der Controller verwendet die ProductsContext
-Klasse, um mithilfe von EF auf die Datenbank zuzugreifen. Beachten Sie, dass der Controller die Dispose-Methode außer Kraft setzt, um den ProductsContext zu entsorgen.
Dies ist der Ausgangspunkt für den Controller. Als Nächstes fügen wir Methoden für alle CRUD-Vorgänge hinzu.
Abfragen des Entitätssatzes
Fügen Sie die folgenden Methoden hinzu ProductsController
.
[EnableQuery]
public IQueryable<Product> Get()
{
return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key)
{
IQueryable<Product> result = db.Products.Where(p => p.Id == key);
return SingleResult.Create(result);
}
Die parameterlose Version der Get
Methode gibt die gesamte Products-Auflistung zurück. Die Get
Methode mit einem Schlüsselparameter sucht ein Produkt nach seinem Schlüssel (in diesem Fall die Id
-Eigenschaft).
Mit dem Attribut [EnableQuery] können Clients die Abfrage mithilfe von Abfrageoptionen wie $filter, $sort und $page ändern. Weitere Informationen finden Sie unter Unterstützung von OData-Abfrageoptionen.
Hinzufügen einer Entität zum Entitätssatz
Um Clients das Hinzufügen eines neuen Produkts zur Datenbank zu ermöglichen, fügen Sie die folgende Methode hinzu ProductsController
.
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return Created(product);
}
Aktualisieren einer Entität
OData unterstützt zwei verschiedene Semantiken zum Aktualisieren einer Entität: PATCH und PUT.
- PATCH führt ein partielles Update aus. Der Client gibt nur die zu aktualisierenden Eigenschaften an.
- PUT ersetzt die gesamte Entität.
Der Nachteil von PUT ist, dass der Client Werte für alle Eigenschaften in der Entität senden muss, einschließlich der Werte, die sich nicht ändern. Die OData-Spezifikation gibt an, dass PATCH bevorzugt ist.
In jedem Fall ist hier der Code für die PATCH- und PUT-Methoden:
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var entity = await db.Products.FindAsync(key);
if (entity == null)
{
return NotFound();
}
product.Patch(entity);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(entity);
}
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
db.Entry(update).State = EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
Im Fall von PATCH verwendet der Controller den Delta<T-Typ> , um die Änderungen nachzuverfolgen.
Löschen einer Entität
Damit Clients ein Produkt aus der Datenbank löschen können, fügen Sie die folgende Methode hinzu ProductsController
.
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
var product = await db.Products.FindAsync(key);
if (product == null)
{
return NotFound();
}
db.Products.Remove(product);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}