Tworzenie punktu końcowego OData w wersji 3 przy użyciu internetowego interfejsu API 2
Autor: Mike Wasson
Pobieranie ukończonego projektu
Protokół OData ( Open Data Protocol ) to protokół dostępu do danych dla sieci Web. OData zapewnia jednolity sposób struktury danych, wykonywania zapytań względem danych i manipulowania zestawem danych za pomocą operacji CRUD (tworzenie, odczytywanie, aktualizowanie i usuwanie). OData obsługuje formaty AtomPub (XML) i JSON. OData definiuje również sposób uwidaczniania metadanych dotyczących danych. Klienci mogą używać metadanych do odnajdywania informacji o typie i relacji dla zestawu danych.
ASP.NET internetowy interfejs API ułatwia tworzenie punktu końcowego OData dla zestawu danych. Możesz kontrolować dokładnie, które operacje OData obsługuje punkt końcowy. Wiele punktów końcowych OData można hostować obok punktów końcowych innych niż OData. Masz pełną kontrolę nad modelem danych, logiką biznesową zaplecza i warstwą danych.
Wersje oprogramowania używane w samouczku
- Visual Studio 2013
- Internetowy interfejs API 2
- OData w wersji 3
- Entity Framework 6
- Serwer proxy debugowania internetowego programu Fiddler (opcjonalnie)
Dodano obsługę OData interfejsu API sieci Web w aktualizacji ASP.NET and Web Tools 2012.2. Jednak w tym samouczku użyto szkieletu dodanego w Visual Studio 2013.
W tym samouczku utworzysz prosty punkt końcowy OData, który klienci mogą wykonywać zapytania. Utworzysz również klienta języka C# dla punktu końcowego. Po ukończeniu tego samouczka następny zestaw samouczków pokazuje, jak dodać więcej funkcji, w tym relacje jednostek, akcje i $expand/$select.
- Tworzenie projektu programu Visual Studio
- Dodawanie modelu jednostki
- Dodawanie kontrolera OData
- Dodawanie EDM i trasy
- Rozmieszczanie bazy danych (opcjonalnie)
- Eksplorowanie punktu końcowego OData
- Formaty serializacji OData
Tworzenie projektu programu Visual Studio
W tym samouczku utworzysz punkt końcowy OData, który obsługuje podstawowe operacje CRUD. Punkt końcowy uwidacznia pojedynczy zasób— listę produktów. W kolejnych samouczkach dodasz więcej funkcji.
Uruchom program 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. Wybierz szablon aplikacji internetowej ASP.NET .
W oknie dialogowym Nowy projekt ASP.NET wybierz szablon Pusty . W obszarze "Dodaj foldery i odwołania podstawowe dla...", sprawdź internetowy interfejs API. Kliknij przycisk OK.
Dodawanie modelu jednostki
Model to obiekt reprezentujący dane w aplikacji. Na potrzeby tego samouczka potrzebujemy modelu reprezentującego produkt. Model odpowiada naszemu typowi jednostki OData.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Models. Z menu kontekstowego wybierz pozycję Dodaj , a następnie wybierz pozycję Klasa.
W oknie dialogowym Dodawanie nowego elementu nadaj klasie nazwę "Product".
Uwaga
Zgodnie z konwencją klasy modeli są umieszczane w folderze Models. Nie musisz przestrzegać tej konwencji we własnych projektach, ale użyjemy jej do tego samouczka.
W pliku Product.cs dodaj następującą definicję klasy:
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
Właściwość ID będzie kluczem jednostki. Klienci mogą wykonywać zapytania dotyczące produktów według identyfikatora. To pole będzie również kluczem podstawowym w bazie danych zaplecza.
Skompiluj projekt teraz. W następnym kroku użyjemy szkieletu programu Visual Studio, który używa odbicia w celu znalezienia typu produktu.
Dodawanie kontrolera OData
Kontroler to klasa, która obsługuje żądania HTTP. Definiujesz oddzielny kontroler dla każdej jednostki ustawionej w usłudze OData. W tym samouczku utworzymy pojedynczy kontroler.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy folder Controllers. Wybierz pozycję Dodaj , a następnie wybierz pozycję Kontroler.
W oknie dialogowym Dodawanie szkieletu wybierz pozycję "Kontroler OData interfejsu API sieci Web 2 z akcjami przy użyciu platformy Entity Framework".
W oknie dialogowym Dodawanie kontrolera nadaj kontrolerowi nazwę "ProductsController". Zaznacz pole wyboru "Użyj akcji kontrolera asynchronicznego". Z listy rozwijanej Model wybierz klasę Product.
Kliknij przycisk Nowy kontekst danych... Pozostaw domyślną nazwę typu kontekstu danych, a następnie kliknij przycisk Dodaj.
Kliknij przycisk Dodaj w oknie dialogowym Dodawanie kontrolera, aby dodać kontroler.
Uwaga: Jeśli zostanie wyświetlony komunikat o błędzie informujący o błędzie "Wystąpił błąd podczas pobierania typu...", upewnij się, że projekt programu Visual Studio został utworzony po dodaniu klasy Product. Szkielet używa odbicia w celu znalezienia klasy.
Szkielet dodaje dwa pliki kodu do projektu:
- Products.cs definiuje kontroler internetowego interfejsu API, który implementuje punkt końcowy OData.
- ProductServiceContext.cs udostępnia metody wykonywania zapytań względem bazowej bazy danych przy użyciu programu Entity Framework.
Dodawanie EDM i trasy
W Eksplorator rozwiązań rozwiń folder App_Start i otwórz plik o nazwie WebApiConfig.cs. Ta klasa przechowuje kod konfiguracji dla internetowego interfejsu API. Zastąp ten kod następującym:
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());
}
}
}
Ten kod wykonuje dwie czynności:
- Tworzy model danych jednostki (EDM) dla punktu końcowego OData.
- Dodaje trasę dla punktu końcowego.
EDM to abstrakcyjny model danych. EDM służy do tworzenia dokumentu metadanych i definiowania identyfikatorów URI dla usługi. ODataConventionModelBuilder tworzy EDM przy użyciu zestawu domyślnych konwencji nazewnictwa EDM. Takie podejście wymaga najmniejszego kodu. Jeśli chcesz mieć większą kontrolę nad modułem EDM, możesz jawnie dodać właściwości, klucze i właściwości nawigacji za pomocą klasy ODataModelBuilder .
Metoda EntitySet dodaje jednostkę ustawioną na EDM:
modelBuilder.EntitySet<Product>("Products");
Ciąg "Products" definiuje nazwę zestawu jednostek. Nazwa kontrolera musi być zgodna z nazwą zestawu jednostek. W tym samouczku zestaw jednostek nosi nazwę "Products", a kontroler ma nazwę ProductsController
. Jeśli nazwano zestaw jednostek "ProductSet", nadasz kontrolerowi ProductSetController
nazwę . Należy pamiętać, że punkt końcowy może mieć wiele zestawów jednostek. Wywołaj metodę EntitySet<T> dla każdego zestawu jednostek, a następnie zdefiniuj odpowiedni kontroler.
Metoda MapODataRoute dodaje trasę dla punktu końcowego OData.
config.Routes.MapODataRoute("ODataRoute", "odata", model);
Pierwszy parametr jest przyjazną nazwą trasy. Klienci usługi nie widzą tej nazwy. Drugi parametr to prefiks identyfikatora URI punktu końcowego. Biorąc pod uwagę ten kod, identyfikator URI zestawu jednostek Products to http:// hostname/odata/Products. Aplikacja może mieć więcej niż jeden punkt końcowy OData. Dla każdego punktu końcowego wywołaj metodę MapODataRoute i podaj unikatową nazwę trasy oraz unikatowy prefiks identyfikatora URI.
Rozmieszczanie bazy danych (opcjonalnie)
W tym kroku użyjesz programu Entity Framework do rozmieszczania bazy danych z niektórymi danymi testowymi. Ten krok jest opcjonalny, ale pozwala od razu przetestować punkt końcowy OData.
W menu Narzędzia wybierz pozycję Menedżer pakietów NuGet, a następnie wybierz pozycję Konsola Menedżera pakietów. W oknie Konsola menedżera pakietów wprowadź następujące polecenie:
Enable-Migrations
Spowoduje to dodanie folderu o nazwie Migrations i pliku kodu o nazwie Configuration.cs.
Otwórz ten plik i dodaj następujący kod do Configuration.Seed
metody .
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" },
});
}
W oknie Konsoli Menedżera pakietów wprowadź następujące polecenia:
Add-Migration Initial
Update-Database
Te polecenia generują kod, który tworzy bazę danych, a następnie wykonuje ten kod.
Eksplorowanie punktu końcowego OData
W tej sekcji użyjemy serwera proxy debugowania internetowego programu Fiddler , aby wysyłać żądania do punktu końcowego i badać komunikaty odpowiedzi. Pomoże to zrozumieć możliwości punktu końcowego OData.
W programie Visual Studio naciśnij klawisz F5, aby rozpocząć debugowanie. Domyślnie program Visual Studio otwiera przeglądarkę na http://localhost:*port*
, gdzie port jest numerem portu skonfigurowanym w ustawieniach projektu.
Numer portu można zmienić w ustawieniach projektu. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Właściwości. W oknie właściwości wybierz pozycję Sieć Web. Wprowadź numer portu w obszarze Adres URL projektu.
Dokument usługi
Dokument usługi zawiera listę zestawów jednostek dla punktu końcowego OData. Aby uzyskać dokument usługi, wyślij żądanie GET do głównego identyfikatora URI usługi.
Za pomocą programu Fiddler wprowadź następujący identyfikator URI na karcie Kompozytor : http://localhost:port/odata/
, gdzie port jest numerem portu.
Kliknij przycisk Wykonaj. Program Fiddler wysyła żądanie HTTP GET do aplikacji. Powinna zostać wyświetlona odpowiedź na liście Sesje sieci Web. Jeśli wszystko działa, kod stanu będzie 200.
Kliknij dwukrotnie odpowiedź na liście Sesje sieci Web, aby wyświetlić szczegóły komunikatu odpowiedzi na karcie Inspektorzy.
Nieprzetworzona odpowiedź HTTP powinna wyglądać podobnie do następującego:
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>
Domyślnie internetowy interfejs API zwraca dokument usługi w formacie AtomPub. Aby zażądać kodu JSON, dodaj następujący nagłówek do żądania HTTP:
Accept: application/json
Teraz odpowiedź HTTP zawiera ładunek JSON:
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"
}
]
}
Dokument metadanych usługi
Dokument metadanych usługi opisuje model danych usługi przy użyciu języka XML o nazwie Koncepcyjny Język definicji schematu (CSDL). Dokument metadanych przedstawia strukturę danych w usłudze i może służyć do generowania kodu klienta.
Aby uzyskać dokument metadanych, wyślij żądanie GET do http://localhost:port/odata/$metadata
. Oto metadane punktu końcowego pokazanego w tym samouczku.
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>
Zestaw jednostek
Aby uzyskać zestaw jednostek Products, wyślij żądanie GET do 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"
}
]
}
Jednostka
Aby uzyskać pojedynczy produkt, wyślij żądanie GET do http://localhost:port/odata/Products(1)
, gdzie "1" jest identyfikatorem produktu.
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"
}
Formaty serializacji OData
Funkcja OData obsługuje kilka formatów serializacji:
- Atom Pub (XML)
- Kod JSON "light" (wprowadzony w usłudze OData v3)
- JSON "verbose" (OData v2)
Domyślnie internetowy interfejs API używa formatu AtomPubJSON "light".
Aby uzyskać format AtomPub, ustaw nagłówek Accept na "application/atom+xml". Oto przykładowa treść odpowiedzi:
<?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>
Widać jedną oczywistą wadę formatu Atom: Jest to o wiele bardziej pełne niż światło JSON. Jeśli jednak masz klienta, który rozumie AtomPub, klient może preferować ten format za pośrednictwem formatu JSON.
Oto jasna wersja JSON tej samej jednostki:
{
"odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element",
"ID":1,
"Name":"Hat",
"Price":"15.00",
"Category":"Apparel"
}
Format światła JSON został wprowadzony w wersji 3 protokołu OData. W celu zapewnienia zgodności z poprzednimi wersjami klient może zażądać starszego formatu JSON "pełnej". Aby zażądać pełnej wartości JSON, ustaw nagłówek Accept na application/json;odata=verbose
. Oto wersja szczegółowa:
{
"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"
}
}
Ten format przekazuje więcej metadanych w treści odpowiedzi, co może zwiększyć obciążenie całej sesji. Ponadto dodaje poziom pośredni poprzez zawijanie obiektu we właściwości o nazwie "d".