Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini menjelaskan konvensi perutean yang digunakan Web API 2 di ASP.NET 4.x untuk titik akhir OData.
Ketika Web API mendapatkan permintaan OData, api memetakan permintaan ke nama pengontrol dan nama tindakan. Pemetaan didasarkan pada metode HTTP dan URI. Misalnya, GET /odata/Products(1) memetakan ke ProductsController.GetProduct.
Di bagian 1 artikel ini, saya menjelaskan konvensi perutean OData bawaan. Konvensi ini dirancang khusus untuk titik akhir OData, dan menggantikan sistem perutean API Web default. (Penggantian terjadi saat Anda memanggil MapODataRoute.)
Di bagian 2, saya menunjukkan cara menambahkan konvensi perutean kustom. Saat ini konvensi bawaan tidak mencakup seluruh rentang URI OData, tetapi Anda dapat memperluasnya untuk menangani kasus tambahan.
Konvensi Perutean Bawaan
Sebelum saya menjelaskan konvensi perutean OData di Api Web, sangat berguna untuk memahami URI OData. URI OData terdiri dari:
- Akar layanan
- Jalur sumber daya
- Opsi kueri
Untuk perutean, bagian pentingnya adalah jalur sumber daya. Jalur sumber daya dibagi menjadi beberapa segmen. Misalnya, /Products(1)/Supplier memiliki tiga segmen:
-
Productsmengacu pada set entitas bernama "Produk". -
1adalah kunci entitas, memilih satu entitas dari set. -
Supplieradalah properti navigasi yang memilih entitas terkait.
Jadi jalur ini memilih pemasok produk 1.
Catatan
Segmen jalur OData tidak selalu sesuai dengan segmen URI. Misalnya, "1" dianggap sebagai segmen jalur.
Nama Pengontrol. Nama pengontrol selalu berasal dari entitas yang ditetapkan di akar jalur sumber daya. Misalnya, jika jalur sumber daya adalah /Products(1)/Supplier, API Web mencari pengontrol bernama ProductsController.
Nama Tindakan. Nama tindakan berasal dari segmen jalur ditambah model data entitas (EDM), seperti yang tercantum dalam tabel berikut. Dalam beberapa kasus, Anda memiliki dua pilihan untuk nama tindakan. Misalnya, "Dapatkan" atau "GetProducts".
Mengkueri Entitas
| Minta | Contoh URI | Nama Tindakan | Contoh Tindakan |
|---|---|---|---|
| GET /entityset | /Produk | GetEntitySet atau Get | GetProducts |
| GET /entityset(key) | /Products(1) | GetEntityType atau Get | GetProduct |
| GET /entityset(key)/cast | /Products(1)/Models.Book | GetEntityType atau Get | GetBook |
Untuk informasi selengkapnya, lihat Membuat titik akhir OData Read-Only.
Membuat, Memperbarui, dan Menghapus Entitas
| Minta | Contoh URI | Nama Tindakan | Contoh Tindakan |
|---|---|---|---|
| POST /entityset | /Produk | PostEntityType atau Post | PostProduct |
| PUT /entityset(key) | /Products(1) | PutEntityType atau Put | PutProduct |
| PUT /entityset(key)/cast | /Products(1)/Models.Book | PutEntityType atau Put | PutBook |
| PATCH /entityset(key) | /Products(1) | PatchEntityType atau Patch | PatchProduct |
| PATCH /entityset(key)/cast | /Products(1)/Models.Book | PatchEntityType atau Patch | PatchBook |
| DELETE /entityset(key) | /Products(1) | DeleteEntityType atau Delete | DeleteProduct |
| DELETE /entityset(key)/cast | /Products(1)/Models.Book | DeleteEntityType atau Delete | DeleteBook |
Mengkueri Properti Navigasi
| Minta | Contoh URI | Nama Tindakan | Contoh Tindakan |
|---|---|---|---|
| GET /entityset(key)/navigation | /Products(1)/Pemasok | GetNavigationFromEntityType atau GetNavigation | GetSupplierFromProduct |
| GET /entityset(key)/cast/navigation | /Products(1)/Models.Book/Author | GetNavigationFromEntityType atau GetNavigation | GetAuthorFromBook |
Untuk informasi selengkapnya, lihat Bekerja dengan Hubungan Entitas.
Membuat dan Menghapus Tautan
| Minta | Contoh URI | Nama Tindakan |
|---|---|---|
| POST /entityset(key)/$links/navigation | /Products(1)/$links/Pemasok | CreateLink |
| PUT /entityset(key)/$links/navigation | /Products(1)/$links/Pemasok | CreateLink |
| DELETE /entityset(key)/$links/navigation | /Products(1)/$links/Pemasok | DeleteLink |
| DELETE /entityset(key)/$links/navigation(relatedKey) | /Products/(1)/$links/Pemasok(1) | DeleteLink |
Untuk informasi selengkapnya, lihat Bekerja dengan Hubungan Entitas.
Properti
Memerlukan Web API 2
| Minta | Contoh URI | Nama Tindakan | Contoh Tindakan |
|---|---|---|---|
| GET /entityset(key)/property | /Products(1)/Name | GetPropertyFromEntityType atau GetProperty | GetNameFromProduct |
| GET /entityset(key)/cast/property | /Products(1)/Models.Book/Author | GetPropertyFromEntityType atau GetProperty | GetTitleFromBook |
Tindakan
| Minta | Contoh URI | Nama Tindakan | Contoh Tindakan |
|---|---|---|---|
| POST /entityset(key)/action | /Products(1)/Rate | ActionNameOnEntityType atau ActionName | RateOnProduct |
| POST /entityset(key)/cast/action | /Products(1)/Models.Book/CheckOut | ActionNameOnEntityType atau ActionName | CheckOutOnBook |
Untuk informasi selengkapnya, lihat Tindakan OData.
Tanda Tangan Metode
Berikut adalah beberapa aturan untuk tanda tangan metode:
- Jika jalur berisi kunci, tindakan harus memiliki parameter bernama kunci.
- Jika jalur berisi kunci ke dalam properti navigasi, tindakan harus memiliki parameter bernama relatedKey.
- Hiasi parameter key dan relatedKey dengan parameter [FromODataUri] .
- Permintaan POST dan PUT mengambil parameter jenis entitas.
- Permintaan PATCH mengambil parameter jenis Delta<T>, di mana T adalah jenis entitas.
Sebagai referensi, berikut adalah contoh yang menunjukkan tanda tangan metode untuk setiap konvensi perutean OData bawaan.
public class ProductsController : ODataController
{
// GET /odata/Products
public IQueryable<Product> Get()
// GET /odata/Products(1)
public Product Get([FromODataUri] int key)
// GET /odata/Products(1)/ODataRouting.Models.Book
public Book GetBook([FromODataUri] int key)
// POST /odata/Products
public HttpResponseMessage Post(Product item)
// PUT /odata/Products(1)
public HttpResponseMessage Put([FromODataUri] int key, Product item)
// PATCH /odata/Products(1)
public HttpResponseMessage Patch([FromODataUri] int key, Delta<Product> item)
// DELETE /odata/Products(1)
public HttpResponseMessage Delete([FromODataUri] int key)
// PUT /odata/Products(1)/ODataRouting.Models.Book
public HttpResponseMessage PutBook([FromODataUri] int key, Book item)
// PATCH /odata/Products(1)/ODataRouting.Models.Book
public HttpResponseMessage PatchBook([FromODataUri] int key, Delta<Book> item)
// DELETE /odata/Products(1)/ODataRouting.Models.Book
public HttpResponseMessage DeleteBook([FromODataUri] int key)
// GET /odata/Products(1)/Supplier
public Supplier GetSupplierFromProduct([FromODataUri] int key)
// GET /odata/Products(1)/ODataRouting.Models.Book/Author
public Author GetAuthorFromBook([FromODataUri] int key)
// POST /odata/Products(1)/$links/Supplier
public HttpResponseMessage CreateLink([FromODataUri] int key,
string navigationProperty, [FromBody] Uri link)
// DELETE /odata/Products(1)/$links/Supplier
public HttpResponseMessage DeleteLink([FromODataUri] int key,
string navigationProperty, [FromBody] Uri link)
// DELETE /odata/Products(1)/$links/Parts(1)
public HttpResponseMessage DeleteLink([FromODataUri] int key, string relatedKey, string navigationProperty)
// GET odata/Products(1)/Name
// GET odata/Products(1)/Name/$value
public HttpResponseMessage GetNameFromProduct([FromODataUri] int key)
// GET /odata/Products(1)/ODataRouting.Models.Book/Title
// GET /odata/Products(1)/ODataRouting.Models.Book/Title/$value
public HttpResponseMessage GetTitleFromBook([FromODataUri] int key)
}
Konvensi Perutean Kustom
Saat ini konvensi bawaan tidak mencakup semua kemungkinan URI OData. Anda dapat menambahkan konvensi baru dengan menerapkan antarmuka IODataRoutingConvention . Antarmuka ini memiliki dua metode:
string SelectController(ODataPath odataPath, HttpRequestMessage request);
string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext,
ILookup<string, HttpActionDescriptor> actionMap);
- PilihKontroler mengembalikan nama pengontrol.
- SelectAction mengembalikan nama tindakan.
Untuk kedua metode, jika konvensi tidak berlaku untuk permintaan tersebut, metode harus mengembalikan null.
Parameter ODataPath mewakili jalur sumber daya OData yang diurai. Ini berisi daftar instans ODataPathSegment , satu untuk setiap segmen jalur sumber daya. ODataPathSegment adalah kelas abstrak; setiap jenis segmen diwakili oleh kelas yang berasal dari ODataPathSegment.
Properti ODataPath.TemplatePath adalah string yang mewakili perangkaian semua segmen jalur. Misalnya, jika URI adalah /Products(1)/Supplier, templat jalurnya adalah "~/entityset/key/navigation". Perhatikan bahwa segmen tidak sesuai langsung dengan segmen URI. Misalnya, kunci entitas (1) direpresentasikan sebagai ODataPathSegment sendiri.
Biasanya, implementasi IODataRoutingConvention melakukan hal berikut:
- Bandingkan templat jalur untuk melihat apakah konvensi ini berlaku untuk permintaan saat ini. Jika tidak berlaku, kembalikan null.
- Jika konvensi berlaku, gunakan properti instans ODataPathSegment untuk mendapatkan pengontrol dan nama tindakan.
- Untuk tindakan, tambahkan nilai apa pun ke kamus rute yang harus mengikat parameter tindakan (biasanya kunci entitas).
Mari kita lihat contoh tertentu. Konvensi perutean bawaan tidak mendukung pengindeksan ke dalam koleksi navigasi. Dengan kata lain, tidak ada konvensi untuk URI seperti berikut:
/odata/Products(1)/Suppliers(1)
Berikut adalah konvensi perutean kustom untuk menangani jenis kueri ini.
using Microsoft.Data.Edm;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;
namespace ODataRouting
{
public class NavigationIndexRoutingConvention : EntitySetRoutingConvention
{
public override string SelectAction(ODataPath odataPath, HttpControllerContext context,
ILookup<string, HttpActionDescriptor> actionMap)
{
if (context.Request.Method == HttpMethod.Get &&
odataPath.PathTemplate == "~/entityset/key/navigation/key")
{
NavigationPathSegment navigationSegment = odataPath.Segments[2] as NavigationPathSegment;
IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty.Partner;
IEdmEntityType declaringType = navigationProperty.DeclaringType as IEdmEntityType;
string actionName = "Get" + declaringType.Name;
if (actionMap.Contains(actionName))
{
// Add keys to route data, so they will bind to action parameters.
KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;
KeyValuePathSegment relatedKeySegment = odataPath.Segments[3] as KeyValuePathSegment;
context.RouteData.Values[ODataRouteConstants.RelatedKey] = relatedKeySegment.Value;
return actionName;
}
}
// Not a match.
return null;
}
}
}
Catatan:
- Saya berasal dari EntitySetRoutingConvention, karena metode SelectController di kelas tersebut sesuai untuk konvensi perutean baru ini. Itu berarti saya tidak perlu mengimplementasikan ulang SelectController.
- Konvensi ini hanya berlaku untuk permintaan GET, dan hanya ketika templat jalur adalah "~/entityset/key/navigation/key".
- Nama tindakan adalah "Get{EntityType}", di mana {EntityType} adalah tipe koleksi navigasi. Misalnya, "GetSupplier". Anda dapat menggunakan konvensi penamaan apa pun yang Anda suka — pastikan tindakan pengontrol Anda cocok.
- Tindakan ini mengambil dua parameter bernama key dan relatedKey. (Untuk daftar beberapa nama parameter yang telah ditentukan sebelumnya, lihat ODataRouteConstants.)
Langkah selanjutnya adalah menambahkan konvensi baru ke daftar konvensi perutean. Ini terjadi selama konfigurasi, seperti yang ditunjukkan dalam kode berikut:
using ODataRouting.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;
namespace ODataRouting
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
// Create EDM (not shown).
// Create the default collection of built-in conventions.
var conventions = ODataRoutingConventions.CreateDefault();
// Insert the custom convention at the start of the collection.
conventions.Insert(0, new NavigationIndexRoutingConvention());
config.Routes.MapODataRoute(routeName: "ODataRoute",
routePrefix: "odata",
model: modelBuilder.GetEdmModel(),
pathHandler: new DefaultODataPathHandler(),
routingConventions: conventions);
}
}
}
Berikut adalah beberapa contoh konvensi perutean lainnya yang berguna untuk ditelaah:
Dan tentu saja Web API itu sendiri adalah sumber terbuka, sehingga Anda dapat melihat kode sumber untuk konvensi perutean bawaan. Ini didefinisikan dalam namespace System.Web.Http.OData.Routing.Conventions .