Włączanie operacji CRUD w interfejsie API sieci Web ASP.NET 1
Autor: Mike Wasson
Pobieranie ukończonego projektu
W tym samouczku pokazano, jak obsługiwać operacje CRUD w usłudze HTTP przy użyciu internetowego interfejsu API ASP.NET dla ASP.NET 4.x.
Wersje oprogramowania używane w samouczku
- Visual Studio 2012
- Internetowy interfejs API 1 (działa również z internetowym interfejsem API 2)
CRUD oznacza "Create, Read, Update i Delete", czyli cztery podstawowe operacje bazy danych. Wiele usług HTTP modeluje również operacje CRUD za pomocą interfejsów API REST lub REST.
W tym samouczku utworzysz bardzo prosty internetowy interfejs API do zarządzania listą produktów. Każdy produkt będzie zawierać nazwę, cenę i kategorię (na przykład "zabawki" lub "sprzęt"), a także identyfikator produktu.
Interfejs API produktów będzie uwidaczniać następujące metody.
Akcja | Metoda HTTP | Względny identyfikator URI |
---|---|---|
Pobieranie listy wszystkich produktów | GET | /api/products |
Pobieranie produktu według identyfikatora | GET | /api/products/id |
Pobieranie produktu według kategorii | GET | /api/products?category=category |
Tworzenie nowego produktu | POST | /api/products |
Aktualizowanie produktu | PUT | /api/products/id |
Usuwanie produktu | DELETE | /api/products/id |
Zwróć uwagę, że niektóre identyfikatory URI zawierają identyfikator produktu w ścieżce. Na przykład, aby uzyskać produkt, którego identyfikator to 28, klient wysyła żądanie GET dla http://hostname/api/products/28
elementu .
Zasoby
Interfejs API produktów definiuje identyfikatory URI dla dwóch typów zasobów:
Zasób | URI |
---|---|
Lista wszystkich produktów. | /api/products |
Produkt indywidualny. | /api/products/id |
Metody
Cztery główne metody HTTP (GET, PUT, POST i DELETE) można mapować na operacje CRUD w następujący sposób:
- Polecenie GET pobiera reprezentację zasobu w określonym identyfikatorze URI. Funkcja GET nie powinna mieć skutków ubocznych na serwerze.
- PUT aktualizuje zasób przy określonym identyfikatorze URI. Funkcja PUT może również służyć do tworzenia nowego zasobu w określonym identyfikatorze URI, jeśli serwer umożliwia klientom określanie nowych identyfikatorów URI. W tym samouczku interfejs API nie będzie obsługiwał tworzenia za pomocą funkcji PUT.
- Post tworzy nowy zasób. Serwer przypisuje identyfikator URI dla nowego obiektu i zwraca ten identyfikator URI w ramach komunikatu odpowiedzi.
- USUWANIE usuwa zasób w określonym identyfikatorze URI.
Uwaga: metoda PUT zastępuje całą jednostkę produktu. Oznacza to, że klient ma wysłać pełną reprezentację zaktualizowanego produktu. Jeśli chcesz obsługiwać aktualizacje częściowe, preferowana jest metoda PATCH. Ten samouczek nie implementuje poprawki.
Tworzenie nowego projektu internetowego interfejsu API
Rozpocznij od uruchomienia programu Visual Studio i wybierz pozycję Nowy projekt na stronie Start . Ewentualnie w menu Plik wybierz pozycję Nowy , a następnie pozycję Projekt.
W okienku Szablony wybierz pozycję Zainstalowane szablony i rozwiń węzeł Visual C# . W obszarze Visual C# wybierz pozycję Sieć Web. Na liście szablonów projektów wybierz pozycję ASP.NET aplikacja internetowa MVC 4. Nadaj projektowi nazwę "ProductStore" i kliknij przycisk OK.
W oknie dialogowym Nowy projekt ASP.NET MVC 4 wybierz pozycję Internetowy interfejs API i kliknij przycisk OK.
Dodawanie modelu
Model to obiekt reprezentujący dane w aplikacji. W ASP.NET internetowego interfejsu API można używać silnie typizowanych obiektów CLR jako modeli i będą one automatycznie serializowane do formatu XML lub JSON dla klienta.
W przypadku interfejsu API magazynu produktów nasze dane składają się z produktów, dlatego utworzymy nową klasę o nazwie Product
.
Jeśli Eksplorator rozwiązań nie jest jeszcze widoczna, kliknij menu Widok i wybierz pozycję Eksplorator rozwiązań. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Models. Z menu kontekstowego wybierz pozycję Dodaj, a następnie wybierz pozycję Klasa. Nadaj klasie nazwę "Product".
Dodaj następujące właściwości do Product
klasy.
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; }
}
}
Dodawanie repozytorium
Musimy przechowywać kolekcję produktów. Dobrym pomysłem jest oddzielenie kolekcji od naszej implementacji usługi. W ten sposób możemy zmienić magazyn zaplecza bez ponownego zapisywania klasy usługi. Ten typ projektu jest nazywany wzorcem repozytorium . Zacznij od zdefiniowania interfejsu ogólnego dla repozytorium.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Models. Wybierz pozycję Dodaj, a następnie wybierz pozycję Nowy element.
W okienku Szablony wybierz pozycję Zainstalowane szablony i rozwiń węzeł C#. W obszarze C#wybierz pozycję Kod. Na liście szablonów kodu wybierz pozycję Interfejs. Nadaj interfejsowi nazwę "IProductRepository".
Dodaj następującą implementację:
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);
}
}
Teraz dodaj kolejną klasę do folderu Models o nazwie "ProductRepository". Ta klasa zaimplementuje IProductRepository
interfejs. Dodaj następującą implementację:
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;
}
}
}
Repozytorium przechowuje listę w pamięci lokalnej. Jest to ok dla samouczka, ale w prawdziwej aplikacji dane są przechowywane zewnętrznie, bazy danych lub w magazynie w chmurze. Wzorzec repozytorium ułatwi później zmianę implementacji.
Dodawanie kontrolera internetowego interfejsu API
Jeśli pracujesz z ASP.NET MVC, znasz już kontrolery. W ASP.NET internetowym interfejsie API kontroler jest klasą, która obsługuje żądania HTTP od klienta. Kreator Nowy projekt utworzył dwa kontrolery podczas tworzenia projektu. Aby je zobaczyć, rozwiń folder Kontrolery w Eksplorator rozwiązań.
- HomeController to tradycyjny kontroler ASP.NET MVC. Jest on odpowiedzialny za obsługę stron HTML dla witryny i nie jest bezpośrednio związany z naszym internetowym interfejsem API.
- ValuesController to przykładowy kontroler WebAPI.
Przejdź do przodu i usuń ValuesController, klikając prawym przyciskiem myszy plik w Eksplorator rozwiązań i wybierając polecenie Usuń. Teraz dodaj nowy kontroler w następujący sposób:
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers. Wybierz pozycję Dodaj , a następnie wybierz pozycję Kontroler.
W kreatorze Dodawanie kontrolera nadaj kontrolerowi nazwę "ProductsController". Z listy rozwijanej Szablon wybierz pozycję Pusty kontroler interfejsu API. Następnie kliknij przycisk Dodaj.
Uwaga
Nie trzeba umieszczać kontrolerów w folderze o nazwie Kontrolery. Nazwa folderu nie jest ważna; jest to po prostu wygodny sposób organizowania plików źródłowych.
Kreator Dodawania kontrolera utworzy plik o nazwie ProductsController.cs w folderze Controllers. Jeśli ten plik nie jest jeszcze otwarty, kliknij dwukrotnie plik, aby go otworzyć. Dodaj następującą instrukcję using :
using ProductStore.Models;
Dodaj pole zawierające wystąpienie IProductRepository .
public class ProductsController : ApiController
{
static readonly IProductRepository repository = new ProductRepository();
}
Uwaga
Wywołanie new ProductRepository()
w kontrolerze nie jest najlepszym projektem, ponieważ łączy kontroler z określoną implementacją IProductRepository
. Aby uzyskać lepsze podejście, zobacz Using the Web API Dependency Resolver (Używanie narzędzia rozpoznawania zależności interfejsu API sieci Web).
Pobieranie zasobu
Interfejs API magazynu produktów uwidacznia kilka akcji "odczyt" jako metody HTTP GET. Każda akcja będzie odpowiadać metodzie ProductsController
w klasie.
Akcja | Metoda HTTP | Względny identyfikator URI |
---|---|---|
Pobieranie listy wszystkich produktów | GET | /api/products |
Pobieranie produktu według identyfikatora | GET | /api/products/id |
Pobieranie produktu według kategorii | GET | /api/products?category=category |
Aby uzyskać listę wszystkich produktów, dodaj tę metodę ProductsController
do klasy:
public class ProductsController : ApiController
{
public IEnumerable<Product> GetAllProducts()
{
return repository.GetAll();
}
// ....
}
Nazwa metody zaczyna się od "Get", więc zgodnie z konwencją jest mapowany na żądania GET. Ponadto, ponieważ metoda nie ma parametrów, mapuje na identyfikator URI, który nie zawiera segmentu "id" w ścieżce.
Aby uzyskać produkt według identyfikatora, dodaj tę metodę ProductsController
do klasy:
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
Ta nazwa metody rozpoczyna się również od "Get", ale metoda ma parametr o nazwie id. Ten parametr jest mapowany na segment "id" ścieżki identyfikatora URI. Struktura internetowego interfejsu API ASP.NET automatycznie konwertuje identyfikator na prawidłowy typ danych (int) dla parametru.
Metoda GetProduct zgłasza wyjątek typu HttpResponseException , jeśli identyfikator jest nieprawidłowy. Ten wyjątek zostanie przetłumaczony przez platformę na błąd 404 (nie znaleziono).
Na koniec dodaj metodę, aby znaleźć produkty według kategorii:
public IEnumerable<Product> GetProductsByCategory(string category)
{
return repository.GetAll().Where(
p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}
Jeśli identyfikator URI żądania ma ciąg zapytania, internetowy interfejs API próbuje dopasować parametry zapytania do parametrów metody kontrolera. W związku z tym identyfikator URI formularza "api/products?category=category" będzie mapować na tę metodę.
Tworzenie zasobu
Następnie dodamy metodę do ProductsController
klasy, aby utworzyć nowy produkt. Oto prosta implementacja metody:
// Not the final implementation!
public Product PostProduct(Product item)
{
item = repository.Add(item);
return item;
}
Zwróć uwagę na dwie kwestie dotyczące tej metody:
- Nazwa metody zaczyna się od "Post...". Aby utworzyć nowy produkt, klient wysyła żądanie HTTP POST.
- Metoda przyjmuje parametr typu Product. W internetowym interfejsie API parametry z typami złożonymi są deserializowane z treści żądania. W związku z tym oczekujemy, że klient wyśle serializowaną reprezentację obiektu produktu w formacie XML lub JSON.
Ta implementacja będzie działać, ale nie jest do końca ukończona. W idealnym przypadku chcemy, aby odpowiedź HTTP zawierała następujące elementy:
- Kod odpowiedzi: Domyślnie platforma internetowego interfejsu API ustawia kod stanu odpowiedzi na wartość 200 (OK). Jednak zgodnie z protokołem HTTP/1.1, gdy żądanie POST powoduje utworzenie zasobu, serwer powinien odpowiedzieć ze stanem 201 (Utworzono).
- Lokalizacji: Gdy serwer tworzy zasób, powinien zawierać identyfikator URI nowego zasobu w nagłówku Lokalizacja odpowiedzi.
ASP.NET internetowy interfejs API ułatwia manipulowanie komunikatem odpowiedzi HTTP. Oto ulepszona implementacja:
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;
}
Zwróć uwagę, że zwracany typ metody to teraz HttpResponseMessage. Zwracając komunikat HttpResponseMessage zamiast produktu, możemy kontrolować szczegóły komunikatu odpowiedzi HTTP, w tym kod stanu i nagłówek Lokalizacja.
Metoda CreateResponse tworzy komunikat HttpResponseMessage i automatycznie zapisuje serializowaną reprezentację obiektu Product w treści komunikatu odpowiedzi.
Uwaga
W tym przykładzie nie jest weryfikowana wartość Product
. Aby uzyskać informacje na temat walidacji modelu, zobacz Walidacja modelu w interfejsie API sieci Web ASP.NET.
Aktualizowanie zasobu
Aktualizowanie produktu przy użyciu funkcji PUT jest proste:
public void PutProduct(int id, Product product)
{
product.Id = id;
if (!repository.Update(product))
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
Nazwa metody zaczyna się od "Put...", więc internetowy interfejs API pasuje do żądań PUT. Metoda przyjmuje dwa parametry, identyfikator produktu i zaktualizowany produkt. Parametr id jest pobierany ze ścieżki identyfikatora URI, a parametr produktu jest deserializowany z treści żądania. Domyślnie struktura internetowego interfejsu API ASP.NET przyjmuje proste typy parametrów z trasy i typów złożonych z treści żądania.
Usuwanie zasobu
Aby usunąć zasób, zdefiniuj element "Usuń..." Metoda.
public void DeleteProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
repository.Remove(id);
}
Jeśli żądanie DELETE powiedzie się, może zwrócić stan 200 (OK) z treścią jednostki opisującego stan; stan 202 (Zaakceptowano), jeśli usunięcie jest nadal oczekujące; lub stan 204 (Brak zawartości) bez treści jednostki. W tym przypadku DeleteProduct
metoda ma typ zwracany void
, więc ASP.NET internetowy interfejs API automatycznie tłumaczy ten kod stanu 204 (Brak zawartości).