Freigeben über


Aktivieren von CRUD-Vorgängen in ASP.NET-Web-API 1

von Mike Wasson

Abgeschlossenes Projekt herunterladen

In diesem Tutorial erfahren Sie, wie Sie CRUD-Vorgänge in einem HTTP-Dienst mithilfe von ASP.NET-Web-API für ASP.NET 4.x unterstützen.

Im Tutorial verwendete Softwareversionen

  • Visual Studio 2012
  • Web-API 1 (funktioniert auch mit Web-API 2)

CRUD steht für "Erstellen, Lesen, Aktualisieren und Löschen", bei denen es sich um die vier grundlegenden Datenbankvorgänge handelt. Viele HTTP-Dienste modellieren auch CRUD-Vorgänge über REST- oder REST-ähnliche APIs.

In diesem Tutorial erstellen Sie eine sehr einfache Web-API zum Verwalten einer Liste von Produkten. Jedes Produkt enthält einen Namen, einen Preis und eine Kategorie (z. B. "Spielzeug" oder "Hardware") sowie eine Produkt-ID.

Die Produkt-API macht die folgenden Methoden verfügbar.

Action HTTP-Methode Relativer URI
Abrufen einer Liste aller Produkte GET /api/products
Abrufen eines Produkts nach ID GET /api/products/id
Abrufen eines Produkts nach Kategorie GET /api/products?category=category
Erstellen eines neuen Produkts POST /api/products
Aktualisieren eines Produkts PUT /api/products/id
Löschen eines Produkts Delete /api/products/id

Beachten Sie, dass einige der URIs die Produkt-ID im Pfad enthalten. Um beispielsweise das Produkt mit der ID 28 abzurufen, sendet der Client eine GET-Anforderung für http://hostname/api/products/28.

Ressourcen

Die Products-API definiert URIs für zwei Ressourcentypen:

Resource URI
Die Liste aller Produkte. /api/products
Ein einzelnes Produkt. /api/products/id

Methoden

Die vier Standard HTTP-Methoden (GET, PUT, POST und DELETE) können CRUD-Vorgängen wie folgt zugeordnet werden:

  • GET ruft die Darstellung der Ressource an einem angegebenen URI ab. GET sollte keine Nebenwirkungen auf dem Server haben.
  • PUT aktualisiert eine Ressource an einem angegebenen URI. PUT kann auch verwendet werden, um eine neue Ressource an einem angegebenen URI zu erstellen, wenn der Server Clients das Angeben neuer URIs zulässt. In diesem Tutorial unterstützt die API die Erstellung über PUT nicht.
  • POST erstellt eine neue Ressource. Der Server weist den URI für das neue Objekt zu und gibt diesen URI als Teil der Antwortnachricht zurück.
  • DELETE löscht eine Ressource an einem angegebenen URI.

Hinweis: Die PUT-Methode ersetzt die gesamte Produktentität. Das heißt, vom Client wird erwartet, dass er eine vollständige Darstellung des aktualisierten Produkts sendet. Wenn Sie Teilupdates unterstützen möchten, wird die PATCH-Methode bevorzugt. In diesem Tutorial wird PATCH nicht implementiert.

Erstellen eines neuen Web-API-Projekts

Führen Sie zunächst Visual Studio aus, und wählen Sie neues Projektauf 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 in der Liste der Projektvorlagen ASP.NET MVC 4-Webanwendung aus. Nennen Sie das Projekt "ProductStore", und klicken Sie auf OK.

Screenshot des neuen Projektfensters mit den Menüoptionen und hervorgehobenem Pfad zum Erstellen einer A S P dot NET M V C 4-Webanwendung.

Wählen Sie im Dialogfeld Neues ASP.NET MVC 4-Projektdie Option Web-API aus, und klicken Sie auf OK.

Screenshot des neuen A S P dot NET-Projekts mit geschachtelten Bildern der verfügbaren Vorlagen und hervorgehobener Web-AD-Vorlage in Blau.

Hinzufügen eines Modells

Ein Modell ist ein Objekt, das für die Daten in Ihrer Anwendung steht. In ASP.NET-Web-API können Sie stark typisierte CLR-Objekte als Modelle verwenden, die automatisch in XML oder JSON für den Client serialisiert werden.

Für die ProductStore-API bestehen unsere Daten aus Produkten, sodass wir eine neue Klasse mit dem Namen Producterstellen.

Wenn der Projektmappen-Explorer nicht bereits sichtbar ist, können Sie auf das Menü Ansicht klicken und Projektmappen-Explorer wählen. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Modelle. Wählen Sie im Kontextmenü Hinzufügen und dann Klasse aus. Nennen Sie die Klasse "Product".

Screenshot des Menüs des Projektmappen-Explorers, in dem die Auswahl für Modelle hervorgehoben ist, um ein zusätzliches Menü zum Auswählen der Option

Fügen Sie der -Klasse die Product folgenden Eigenschaften hinzu.

namespace ProductStore.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }
    }
}

Hinzufügen eines Repositorys

Wir müssen eine Sammlung von Produkten speichern. Es ist eine gute Idee, die Sammlung von unserer Dienstimplementierung zu trennen. Auf diese Weise können wir den Sicherungsspeicher ändern, ohne die Dienstklasse neu zu schreiben. Dieser Typ von Entwurf wird als Repositorymuster bezeichnet. Definieren Sie zunächst eine generische Schnittstelle für das Repository.

Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Modelle. Wählen Sie Hinzufügen und dann Neues Element aus.

Screenshot des Menüs des Projektmappen-Explorers, in dem die Option

Wählen Sie im Bereich Vorlagendie Option Installierte Vorlagen aus, und erweitern Sie den Knoten C#. Wählen Sie unter C# die Option Code aus. Wählen Sie in der Liste der Codevorlagen die Option Schnittstelle aus. Nennen Sie die Schnittstelle "IProductRepository".

Screenshot des Vorlagenbereichs mit dem Menü

Fügen Sie die folgende Implementierung hinzu:

namespace ProductStore.Models
{
    public interface IProductRepository
    {
        IEnumerable<Product> GetAll();
        Product Get(int id);
        Product Add(Product item);
        void Remove(int id);
        bool Update(Product item);
    }
}

Fügen Sie nun dem Ordner Models eine weitere Klasse mit dem Namen "ProductRepository" hinzu. Diese Klasse implementiert die IProductRepository -Schnittstelle. Fügen Sie die folgende Implementierung hinzu:

namespace ProductStore.Models
{
    public class ProductRepository : IProductRepository
    {
        private List<Product> products = new List<Product>();
        private int _nextId = 1;

        public ProductRepository()
        {
            Add(new Product { Name = "Tomato soup", Category = "Groceries", Price = 1.39M });
            Add(new Product { Name = "Yo-yo", Category = "Toys", Price = 3.75M });
            Add(new Product { Name = "Hammer", Category = "Hardware", Price = 16.99M });
        }

        public IEnumerable<Product> GetAll()
        {
            return products;
        }

        public Product Get(int id)
        {
            return products.Find(p => p.Id == id);
        }

        public Product Add(Product item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            item.Id = _nextId++;
            products.Add(item);
            return item;
        }

        public void Remove(int id)
        {
            products.RemoveAll(p => p.Id == id);
        }

        public bool Update(Product item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            int index = products.FindIndex(p => p.Id == item.Id);
            if (index == -1)
            {
                return false;
            }
            products.RemoveAt(index);
            products.Add(item);
            return true;
        }
    }
}

Das Repository speichert die Liste im lokalen Speicher. Dies ist für ein Tutorial in Ordnung, aber in einer echten Anwendung würden Sie die Daten extern speichern, entweder in einer Datenbank oder im Cloudspeicher. Das Repositorymuster erleichtert es, die Implementierung später zu ändern.

Hinzufügen eines Web-API-Controllers

Wenn Sie mit ASP.NET MVC gearbeitet haben, sind Sie bereits mit Controllern vertraut. In ASP.NET-Web-API ist ein Controller eine Klasse, die HTTP-Anforderungen vom Client verarbeitet. Der Assistent neues Projekt hat beim Erstellen des Projekts zwei Controller für Sie erstellt. Um sie anzuzeigen, erweitern Sie den Ordner Controller in Projektmappen-Explorer.

  • HomeController ist ein herkömmlicher ASP.NET MVC-Controller. Sie ist für die Bereitstellung von HTML-Seiten für die Website verantwortlich und steht nicht in direktem Zusammenhang mit unserer Web-API.
  • ValuesController ist ein WebAPI-Beispielcontroller.

Löschen Sie ValuesController, indem Sie mit der rechten Maustaste auf die Datei in Projektmappen-Explorer klicken und Löschen auswählen. Fügen Sie nun wie folgt einen neuen Controller hinzu:

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner „Controller“. Wählen Sie Hinzufügen und dann Controller.

Screenshot des Menüs des Projektmappen-Explorers mit Hervorhebung der Controllerkategorie, die ein weiteres Menü enthält, in dem der Pfad zum Hinzufügen eines Controllers hervorgehoben wird.

Nennen Sie den Controller im Assistenten Zum Hinzufügen von Controllern den Namen "ProductsController". Wählen Sie in der Dropdownliste Vorlage die Option Leerer API-Controller aus. Klicken Sie anschließend auf Hinzufügen.

Screenshot des Fensters

Hinweis

Es ist nicht erforderlich, Ihre Controller in einen Ordner namens Controller zu speichern. Der Ordnername ist nicht wichtig. Es ist einfach eine bequeme Möglichkeit, Ihre Quelldateien zu organisieren.

Der Assistent zum Hinzufügen von Controllern erstellt im Ordner Controller eine Datei namens ProductsController.cs. Doppelklicken Sie auf die Datei, um sie zu öffnen, falls sie noch nicht geöffnet ist. Fügen Sie die folgende using-Anweisung hinzu:

using ProductStore.Models;

Fügen Sie ein Feld hinzu, das eine IProductRepository-instance enthält.

public class ProductsController : ApiController
{
    static readonly IProductRepository repository = new ProductRepository();
}

Hinweis

Das Aufrufen new ProductRepository() des Controllers ist nicht der beste Entwurf, da er den Controller an eine bestimmte Implementierung von IProductRepositorybindet. Einen besseren Ansatz finden Sie unter Verwenden des Abhängigkeitslösers der Web-API.

Abrufen einer Ressource

Die ProductStore-API macht mehrere "Leseaktionen" als HTTP GET-Methoden verfügbar. Jede Aktion entspricht einer Methode in der ProductsController -Klasse.

Action HTTP-Methode Relativer URI
Abrufen einer Liste aller Produkte GET /api/products
Abrufen eines Produkts nach ID GET /api/products/id
Abrufen eines Produkts nach Kategorie GET /api/products?category=category

Um die Liste aller Produkte abzurufen, fügen Sie der ProductsController -Klasse diese Methode hinzu:

public class ProductsController : ApiController
{
    public IEnumerable<Product> GetAllProducts()
    {
        return repository.GetAll();
    }
    // ....
}

Der Methodenname beginnt mit "Get", sodass er gemäß der Konvention GET-Anforderungen zugeordnet wird. Da die Methode auch keine Parameter aufweist, wird sie einem URI zugeordnet, der kein "id"- Segment im Pfad enthält.

Um ein Produkt nach ID abzurufen, fügen Sie der ProductsController -Klasse diese Methode hinzu:

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound); 
    }
    return item;
}

Dieser Methodenname beginnt auch mit "Get", aber die Methode verfügt über einen Parameter namens id. Dieser Parameter wird dem "id"-Segment des URI-Pfads zugeordnet. Das ASP.NET-Web-API Framework konvertiert die ID automatisch in den richtigen Datentyp (int) für den Parameter.

Die GetProduct-Methode löst eine Ausnahme vom Typ HttpResponseException aus, wenn die ID ungültig ist. Diese Ausnahme wird vom Framework in einen Fehler 404 (Nicht gefunden) übersetzt.

Fügen Sie schließlich eine Methode hinzu, um Produkte nach Kategorie zu finden:

public IEnumerable<Product> GetProductsByCategory(string category)
{
    return repository.GetAll().Where(
        p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}

Wenn der Anforderungs-URI über eine Abfragezeichenfolge verfügt, versucht die Web-API, die Abfrageparameter mit Parametern für die Controllermethode abzugleichen. Daher wird dieser Methode ein URI des Formulars "api/products?category=category" zugeordnet.

Erstellen einer Ressource

Als Nächstes fügen wir der ProductsController -Klasse eine Methode hinzu, um ein neues Produkt zu erstellen. Hier sehen Sie eine einfache Implementierung der Methode:

// Not the final implementation!
public Product PostProduct(Product item)
{
    item = repository.Add(item);
    return item;
}

Beachten Sie zwei Dinge zu dieser Methode:

  • Der Methodenname beginnt mit "Post...". Um ein neues Produkt zu erstellen, sendet der Client eine HTTP POST-Anforderung.
  • Die -Methode nimmt einen Parameter vom Typ Product an. In der Web-API werden Parameter mit komplexen Typen aus dem Anforderungstext deserialisiert. Daher erwarten wir, dass der Client eine serialisierte Darstellung eines Produktobjekts im XML- oder JSON-Format sendet.

Diese Implementierung funktioniert, ist aber noch nicht ganz abgeschlossen. Idealerweise sollte die HTTP-Antwort Folgendes enthalten:

  • Antwortcode: Standardmäßig legt das Web-API-Framework die Antwort status Code auf 200 (OK) fest. Gemäß dem HTTP/1.1-Protokoll sollte der Server jedoch mit status 201 (Erstellt) antworten, wenn eine POST-Anforderung zur Erstellung einer Ressource führt.
  • Lage: Wenn der Server eine Ressource erstellt, sollte sie den URI der neuen Ressource im Location-Header der Antwort enthalten.

ASP.NET-Web-API erleichtert die Bearbeitung der HTTP-Antwortnachricht. Hier sehen Sie die verbesserte Implementierung:

public HttpResponseMessage PostProduct(Product item)
{
    item = repository.Add(item);
    var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);

    string uri = Url.Link("DefaultApi", new { id = item.Id });
    response.Headers.Location = new Uri(uri);
    return response;
}

Beachten Sie, dass der Methodenrückgabetyp jetzt HttpResponseMessage ist. Durch Zurückgeben einer HttpResponseMessage anstelle eines Product können wir die Details der HTTP-Antwortnachricht steuern, einschließlich des status-Codes und des Location-Headers.

Die CreateResponse-Methode erstellt eine HttpResponseMessage und schreibt automatisch eine serialisierte Darstellung des Product-Objekts in den Text der Antwortnachricht.

Hinweis

In diesem Beispiel wird nicht Productüberprüft. Informationen zur Modellüberprüfung finden Sie unter Modellvalidierung in ASP.NET-Web-API.

Aktualisieren einer Ressource

Das Aktualisieren eines Produkts mit PUT ist einfach:

public void PutProduct(int id, Product product)
{
    product.Id = id;
    if (!repository.Update(product))
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}

Der Methodenname beginnt mit "Put...", sodass die Web-API ihn mit PUT-Anforderungen abgleicht. Die Methode benötigt zwei Parameter, die Produkt-ID und das aktualisierte Produkt. Der id-Parameter wird aus dem URI-Pfad entnommen, und der Product-Parameter wird aus dem Anforderungstext deserialisiert. Standardmäßig akzeptiert das ASP.NET-Web-API Framework einfache Parametertypen aus der Route und komplexe Typen aus dem Anforderungstext.

Löschen einer Ressource

Um eine Ressource zu löschen, definieren Sie "Löschen..." Methode.

public void DeleteProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    repository.Remove(id);
}

Wenn eine DELETE-Anforderung erfolgreich ist, kann sie status 200 (OK) mit einem Entitätstext zurückgeben, der die status beschreibt. status 202 (Akzeptiert), wenn der Löschvorgang noch aussteht; oder status 204 (Kein Inhalt) ohne Entitätstext. In diesem Fall verfügt die DeleteProduct Methode über einen void Rückgabetyp, sodass ASP.NET-Web-API dies automatisch in status Code 204 (No Content) übersetzt.