Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
door Mike Wasson
Deze zelfstudie laat zien hoe u CRUD-bewerkingen in een HTTP-service kunt ondersteunen met behulp van ASP.NET Web-API voor ASP.NET 4.x.
Softwareversies die in de zelfstudie worden gebruikt
- Visual Studio 2012
- Web-API 1 (werkt ook met Web-API 2)
CRUD staat voor 'Maken, Lezen, Bijwerken en Verwijderen'. Dit zijn de vier basisdatabasebewerkingen. Veel HTTP-services modelleren ook CRUD-bewerkingen via REST- of REST-achtige API's.
In deze zelfstudie bouwt u een zeer eenvoudige web-API om een lijst met producten te beheren. Elk product bevat een naam, prijs en categorie (zoals 'speelgoed' of 'hardware'), plus een product-id.
De producten-API biedt de volgende methoden.
| Action | HTTP-methode | Relatieve URI |
|---|---|---|
| Een lijst met alle producten ophalen | GET | /api/products |
| Een product ophalen op basis van id | GET | /api/products/id |
| Een product op categorie ophalen | GET | /api/products?category=category |
| Een nieuw product maken | POST | /api/products |
| Een product bijwerken | PUT | /api/products/id |
| Een product verwijderen | Verwijderen | /api/products/id |
U ziet dat sommige URI's de product-id in het pad bevatten. Als u bijvoorbeeld het product wilt ophalen waarvan de id 28 is, verzendt de client een GET-aanvraag voor http://hostname/api/products/28.
Middelen
De api voor producten definieert URI's voor twee resourcetypen:
| Hulpbron | URI |
|---|---|
| De lijst met alle producten. | /api/products |
| Een afzonderlijk product. | /api/products/id |
Methods
De vier belangrijkste HTTP-methoden (GET, PUT, POST en DELETE) kunnen als volgt worden toegewezen aan CRUD-bewerkingen:
- GET haalt de weergave van de resource op een opgegeven URI op. GET mag geen bijwerkingen hebben op de server.
- PUT werkt een resource bij op een opgegeven URI. PUT kan ook worden gebruikt om een nieuwe resource te maken op een opgegeven URI, als de server clients toestaat nieuwe URI's op te geven. Voor deze zelfstudie biedt de API geen ondersteuning voor het maken via PUT.
- POST maakt een nieuwe resource. De server wijst de URI voor het nieuwe object toe en retourneert deze URI als onderdeel van het antwoordbericht.
- Delete verwijdert een resource op een opgegeven URI.
Opmerking: De PUT-methode vervangt de hele productentiteit. Dat wil dus dat de client naar verwachting een volledige weergave van het bijgewerkte product verzendt. Als u gedeeltelijke updates wilt ondersteunen, heeft de PATCH-methode de voorkeur. In deze zelfstudie wordt PATCH niet geïmplementeerd.
Een nieuw web-API-project maken
Begin met het uitvoeren van Visual Studio en selecteer Nieuw projectop de startpagina . Of selecteer in het menu Bestand de optie Nieuw en vervolgens Project.
Selecteer Geïnstalleerde sjablonen in het deelvenster Sjablonen en vouw het knooppunt Visual C# uit. Selecteer onder Visual C#Web. Selecteer ASP.NET MVC 4-webtoepassing in de lijst met projectsjablonen. Geef het project de naam ProductStore en klik op OK.
Selecteer web-API in het dialoogvenster Nieuw ASP.NET MVC 4-project en klik op OK.
Een model toevoegen
Een model is een object dat de gegevens in uw toepassing vertegenwoordigt. In ASP.NET Web-API kunt u sterk getypte CLR-objecten als modellen gebruiken. Ze worden automatisch geserialiseerd naar XML of JSON voor de client.
Voor de ProductStore-API bestaan onze gegevens uit producten, dus maken we een nieuwe klasse met de naam Product.
Als Solution Explorer nog niet zichtbaar is, klikt u op het menu Beeld en selecteert u Solution Explorer. Klik in Solution Explorer met de rechtermuisknop op de map Modellen . Selecteer Toevoegen in het contextmenu en selecteer vervolgens Klasse. Noem de klasse Product.
Voeg de volgende eigenschappen toe aan de Product klasse.
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; }
}
}
Een opslagplaats toevoegen
We moeten een verzameling producten opslaan. Het is een goed idee om de verzameling te scheiden van onze service-implementatie. Op die manier kunnen we de opslagstructuur wijzigen zonder de serviceklasse te herschrijven. Dit type ontwerp wordt het patroon van de opslagplaats genoemd. Begin met het definiëren van een algemene interface voor de opslagplaats.
Klik in Solution Explorer met de rechtermuisknop op de map Modellen . Selecteer Toevoegen en selecteer vervolgens Nieuw item.
Selecteer Geïnstalleerde sjablonen in het deelvenster Sjablonen en vouw het C#-knooppunt uit. Selecteer Onder C# de optie Code. Selecteer Interface in de lijst met codesjablonen. Noem de interface 'IProductRepository'.
Voeg de volgende implementatie toe:
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);
}
}
Voeg nu nog een klasse toe aan de map Modellen, met de naam ProductRepository. Met deze klasse wordt de IProductRepository interface geïmplementeerd. Voeg de volgende implementatie toe:
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;
}
}
}
De opslagplaats bewaart de lijst in het lokale geheugen. Dit is in orde voor een zelfstudie, maar in een echte toepassing slaat u de gegevens extern op, ofwel een database of in cloudopslag. Met het opslagplaatspatroon kunt u de implementatie later gemakkelijker wijzigen.
Een web-API-controller toevoegen
Als u met ASP.NET MVC hebt gewerkt, bent u al bekend met controllers. In ASP.NET Web-API is een controller een klasse die HTTP-aanvragen van de client verwerkt. De wizard Nieuw project heeft twee controllers voor u gemaakt bij het aanmaken van het project. Als u ze wilt zien, vouwt u de map Controllers uit in Solution Explorer.
- HomeController is een traditionele ASP.NET MVC-controller. Het is verantwoordelijk voor het leveren van HTML-pagina's voor de site en is niet rechtstreeks gerelateerd aan onze web-API.
- ValuesController is een voorbeeld van een WebAPI-controller.
Verwijder ValuesController door met de rechtermuisknop op het bestand in Solution Explorer te klikken en Delete te selecteren . Voeg nu als volgt een nieuwe controller toe:
Klik in Solution Explorer met de rechtermuisknop op de map Controllers. Selecteer Toevoegen en selecteer vervolgens Controller.
Geef in de wizard Controller toevoegen de controller de naam 'ProductsController'. Selecteer in de vervolgkeuzelijst Sjabloon de optie lege API-controller. Klik vervolgens op Toevoegen.
Opmerking
Het is niet nodig om uw controllers in een map met de naam Controllers te plaatsen. De mapnaam is niet belangrijk; het is gewoon een handige manier om uw bronbestanden te organiseren.
De wizard Controller toevoegen maakt een bestand met de naam ProductsController.cs in de map Controllers. Als dit bestand nog niet is geopend, dubbelklikt u op het bestand om het te openen. Voeg de volgende using-instructie toe:
using ProductStore.Models;
Voeg een veld toe dat een IProductRepository-exemplaar bevat.
public class ProductsController : ApiController
{
static readonly IProductRepository repository = new ProductRepository();
}
Opmerking
Het aanroepen new ProductRepository() van de controller is niet het beste ontwerp, omdat deze de controller koppelt aan een bepaalde implementatie van IProductRepository. Zie Het gebruik van de web-API-afhankelijkheidsresolver voor een betere aanpak.
Een resource verkrijgen
Met de ProductStore-API worden verschillende leesacties weergegeven als HTTP GET-methoden. Elke actie komt overeen met een methode in de ProductsController klasse.
| Action | HTTP-methode | Relatieve URI |
|---|---|---|
| Een lijst met alle producten ophalen | GET | /api/products |
| Een product ophalen op basis van id | GET | /api/products/id |
| Een product op categorie ophalen | GET | /api/products?category=category |
Als u de lijst met alle producten wilt ophalen, voegt u deze methode toe aan de ProductsController klasse:
public class ProductsController : ApiController
{
public IEnumerable<Product> GetAllProducts()
{
return repository.GetAll();
}
// ....
}
De naam van de methode begint met 'Get', dus volgens de conventie wordt deze toegewezen aan GET-aanvragen. Omdat de methode geen parameters heeft, wordt deze toegewezen aan een URI die geen id-segment in het pad bevat.
Als u een product op id wilt ophalen, voegt u deze methode toe aan de ProductsController klasse:
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
Deze methodenaam begint ook met 'Get', maar de methode heeft een parameter met de naam id. Deze parameter wordt toegewezen aan het segment 'id' van het URI-pad. Het ASP.NET Web API-framework converteert de id automatisch naar het juiste gegevenstype (int) voor de parameter.
De Methode GetProduct genereert een uitzondering van het type HttpResponseException als de id niet geldig is. Deze uitzondering wordt door het framework omgezet in een 404-fout (niet gevonden).
Voeg ten slotte een methode toe om producten op categorie te vinden:
public IEnumerable<Product> GetProductsByCategory(string category)
{
return repository.GetAll().Where(
p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}
Als de aanvraag-URI een querytekenreeks heeft, probeert de web-API de queryparameters te koppelen aan parameters op de controllermethode. Daarom zal een URI van de vorm 'api/products?category=category' aan deze methode worden toegewezen.
Een resource maken
Vervolgens voegen we een methode toe aan de ProductsController klasse om een nieuw product te maken. Hier volgt een eenvoudige implementatie van de methode:
// Not the final implementation!
public Product PostProduct(Product item)
{
item = repository.Add(item);
return item;
}
Let op twee dingen over deze methode:
- De naam van de methode begint met 'Post...'. Om een nieuw product te maken, verzendt de client een HTTP POST-aanvraag.
- De methode gebruikt een parameter van het type Product. In de web-API worden parameters met complexe typen gedeserialiseerd vanuit de hoofdtekst van de aanvraag. Daarom verwachten we dat de client een geserialiseerde weergave van een productobject verzendt, in XML- of JSON-indeling.
Deze implementatie werkt wel, maar het is niet helemaal voltooid. In het ideale voorbeeld willen we dat het HTTP-antwoord het volgende bevat:
- Antwoordcode: Standaard stelt het Web API-framework de antwoordstatuscode in op 200 (OK). Maar volgens het HTTP/1.1-protocol, wanneer een POST-aanvraag resulteert in het maken van een resource, moet de server reageren met de status 201 (gemaakt).
- Locatie: Wanneer de server een resource maakt, moet deze de URI van de nieuwe resource bevatten in de locatieheader van het antwoord.
ASP.NET Web-API maakt het eenvoudig om het HTTP-antwoordbericht te bewerken. Dit is de verbeterde implementatie:
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;
}
U ziet dat het retourtype methode nu HttpResponseMessage is. Door een HttpResponseMessage te retourneren in plaats van een product, kunnen we de details van het HTTP-antwoordbericht beheren, inclusief de statuscode en de locatieheader.
De methode CreateResponse maakt een HttpResponseMessage en schrijft automatisch een geserialiseerde weergave van het productobject naar de hoofdtekst van het antwoordbericht.
Opmerking
Dit voorbeeld valideert de Product niet. Zie Modelvalidatie in ASP.NET Web-API voor meer informatie over modelvalidatie.
Een resource bijwerken
Het bijwerken van een product met PUT is eenvoudig:
public void PutProduct(int id, Product product)
{
product.Id = id;
if (!repository.Update(product))
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
De naam van de methode begint met 'Put...', dus de web-API komt overeen met PUT-aanvragen. De methode gebruikt twee parameters, de product-id en het bijgewerkte product. De id-parameter wordt opgehaald uit het URI-pad en de productparameter wordt gedeserialiseerd vanuit de aanvraagbody. Standaard gebruikt het ASP.NET Web API-framework eenvoudige parametertypen van de route en complexe typen uit de aanvraagbody.
Een resource verwijderen
Als u een resource wilt verwijderen, definieert u een 'Verwijderen...' Methode.
public void DeleteProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
repository.Remove(id);
}
Als een DELETE-aanvraag slaagt, kan deze status 200 (OK) retourneren met een entiteitstekst die de status beschrijft; status 202 (geaccepteerd) als de verwijdering nog in behandeling is; of status 204 (Geen inhoud) zonder entiteitstekst. In dit geval heeft de DeleteProduct methode een void retourtype, dus ASP.NET web-API dit automatisch vertaalt in statuscode 204 (geen inhoud).