Bagikan melalui


Membuat Titik Akhir OData v4 Menggunakan API Web ASP.NET

Open Data Protocol (OData) adalah protokol akses data untuk web. OData menyediakan cara yang seragam untuk mengkueri dan memanipulasi himpunan data melalui operasi CRUD (membuat, membaca, memperbarui, dan menghapus).

ASP.NET Web API mendukung protokol v3 dan v4. Anda bahkan dapat memiliki titik akhir v4 yang berjalan berdampingan dengan titik akhir v3.

Tutorial ini menunjukkan cara membuat titik akhir OData v4 yang mendukung operasi CRUD.

Versi perangkat lunak yang digunakan dalam tutorial

  • WEB API 5.2
  • OData v4
  • Visual Studio 2017 (unduh Visual Studio 2017 di sini)
  • Entity Framework 6
  • .NET 4.7.2

Versi tutorial

Untuk OData Versi 3, lihat Membuat Titik Akhir OData v3.

Membuat Proyek Visual Studio

Di Visual Studio, dari menu File, pilihProyekBaru>.

PerluasVisual C#>Webyang Terinstal>, dan pilih templat Aplikasi Web ASP.NET (.NET Framework). Beri nama proyek "ProductService".

Cuplikan layar jendela proyek baru visual studio, memperlihatkan opsi menu untuk membuat Aplikasi Web A S P dot NET dengan dot NET Framework.

PilihOK.

Cuplikan layar Aplikasi Web A S P dot NET, memperlihatkan templat yang tersedia untuk membuat aplikasi dengan folder Web A P I dan referensi inti.

Pilih templat Tugas kosong. Di bawah Tambahkan folder dan referensi inti untuk:, pilih WEB API. PilihOK.

Menginstal paket OData

Dari menu Alat, pilih Pengelola Paket NuGet>Konsol Pengelola Paket. Di jendela Konsol Pengelola Paket, ketik:

Install-Package Microsoft.AspNet.Odata

Perintah ini menginstal paket OData NuGet terbaru.

Menambahkan kelas model

Model adalah objek yang mewakili entitas data di aplikasi Anda.

Di Penjelajah Solusi, klik kanan folder Model. Dari menu konteks, pilih Tambahkan>Kelas.

Cuplikan layar jendela penjelajah solusi, menyoroti jalur untuk menambahkan objek kelas model ke proyek.

Catatan

Berdasarkan konvensi, kelas model ditempatkan di folder Model, tetapi Anda tidak perlu mengikuti konvensi ini dalam proyek Anda sendiri.

Beri nama kelas Product. Dalam file Product.cs, ganti kode boilerplate dengan yang berikut:

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

Properti Id adalah kunci entitas. Klien dapat mengkueri entitas berdasarkan kunci. Misalnya, untuk mendapatkan produk dengan ID 5, URI adalah /Products(5). Properti Id juga akan menjadi kunci utama dalam database back-end.

Aktifkan Kerangka Kerja Entitas

Untuk tutorial ini, kita akan menggunakan Kode Kerangka Kerja Entitas (EF) Terlebih Dahulu untuk membuat database back-end.

Catatan

OData API Web tidak memerlukan EF. Gunakan lapisan akses data apa pun yang dapat menerjemahkan entitas database ke dalam model.

Pertama, instal paket NuGet untuk EF. Dari menu Alat, pilih Pengelola Paket NuGet>Konsol Pengelola Paket. Di jendela Konsol Pengelola Paket, ketik:

Install-Package EntityFramework

Buka file Web.config, dan tambahkan bagian berikut di dalam elemen konfigurasi , setelah elemen configSections .

<configuration>
  <configSections>
    <!-- ... -->
  </configSections>

  <!-- Add this: -->
  <connectionStrings>
    <add name="ProductsContext" connectionString="Data Source=(localdb)\mssqllocaldb; 
        Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True; 
        AttachDbFilename=|DataDirectory|ProductsContext.mdf"
      providerName="System.Data.SqlClient" />
  </connectionStrings>

Pengaturan ini menambahkan string koneksi untuk database LocalDB. Database ini akan digunakan saat Anda menjalankan aplikasi secara lokal.

Selanjutnya, tambahkan kelas bernama ProductsContext ke folder Model:

using System.Data.Entity;
namespace ProductService.Models
{
    public class ProductsContext : DbContext
    {
        public ProductsContext() 
                : base("name=ProductsContext")
        {
        }
        public DbSet<Product> Products { get; set; }
    }
}

Di konstruktor, "name=ProductsContext" berikan nama string koneksi.

Mengonfigurasi titik akhir OData

Buka file App_Start/WebApiConfig.cs. Tambahkan pernyataan penggunaan berikut:

using ProductService.Models;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;

Kemudian tambahkan kode berikut ke metode Register :

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // New code:
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Product>("Products");
        config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: null,
            model: builder.GetEdmModel());
    }
}

Kode ini melakukan dua hal:

  • Membuat Model Data Entitas (EDM).
  • Menambahkan rute.

EDM adalah model abstrak data. EDM digunakan untuk membuat dokumen metadata layanan. Kelas ODataConventionModelBuilder membuat EDM dengan menggunakan konvensi penamaan default. Pendekatan ini membutuhkan kode paling sedikit. Jika Anda ingin kontrol lebih besar atas EDM, Anda dapat menggunakan kelas ODataModelBuilder untuk membuat EDM dengan menambahkan properti, kunci, dan properti navigasi secara eksplisit.

Rute memberi tahu Web API cara merutekan permintaan HTTP ke titik akhir. Untuk membuat rute OData v4, panggil metode ekstensi MapODataServiceRoute .

Jika aplikasi Anda memiliki beberapa titik akhir OData, buat rute terpisah untuk masing-masing titik akhir. Beri setiap rute nama rute dan awalan yang unik.

Menambahkan pengontrol OData

Pengontrol adalah kelas yang menangani permintaan HTTP. Anda membuat pengontrol terpisah untuk setiap entitas yang diatur dalam layanan OData Anda. Dalam tutorial ini, Anda akan membuat satu pengontrol, untuk Product entitas.

Di Penjelajah Solusi, klik kanan folder Pengontrol dan pilih Tambahkan>Kelas. Beri nama kelas ProductsController.

Catatan

Versi tutorial ini untuk OData v3 menggunakan perancah Tambahkan Pengontrol . Saat ini, tidak ada perancah untuk OData v4.

Ganti kode boilerplate di ProductsController.cs dengan yang berikut ini.

using ProductService.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
namespace ProductService.Controllers
{
    public class ProductsController : ODataController
    {
        ProductsContext db = new ProductsContext();
        private bool ProductExists(int key)
        {
            return db.Products.Any(p => p.Id == key);
        } 
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}

Pengontrol menggunakan ProductsContext kelas untuk mengakses database menggunakan EF. Perhatikan bahwa pengontrol mengambil alih metode Buang untuk membuang ProductsContext.

Ini adalah titik awal untuk pengontrol. Selanjutnya, kita akan menambahkan metode untuk semua operasi CRUD.

Mengkueri kumpulan entitas

Tambahkan metode berikut ke ProductsController.

[EnableQuery]
public IQueryable<Product> Get()
{
    return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key)
{
    IQueryable<Product> result = db.Products.Where(p => p.Id == key);
    return SingleResult.Create(result);
}

Versi metode tanpa Get parameter mengembalikan seluruh koleksi Produk. Metode Get dengan parameter kunci mencari produk dengan kuncinya (dalam hal ini, Id properti ).

Atribut [EnableQuery] memungkinkan klien mengubah kueri, dengan menggunakan opsi kueri seperti $filter, $sort, dan $page. Untuk informasi selengkapnya, lihat Mendukung Opsi Kueri OData.

Menambahkan entitas ke set entitas

Untuk memungkinkan klien menambahkan produk baru ke database, tambahkan metode berikut ke ProductsController.

public async Task<IHttpActionResult> Post(Product product)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    db.Products.Add(product);
    await db.SaveChangesAsync();
    return Created(product);
}

Memperbarui entitas

OData mendukung dua semantik yang berbeda untuk memperbarui entitas, PATCH dan PUT.

  • PATCH melakukan pembaruan parsial. Klien hanya menentukan properti yang akan diperbarui.
  • PUT menggantikan seluruh entitas.

Kerugian put adalah klien harus mengirim nilai untuk semua properti dalam entitas, termasuk nilai yang tidak berubah. Spesifikasi OData menyatakan bahwa PATCH lebih disukai.

Bagaimanapun, berikut adalah kode untuk metode PATCH dan PUT:

public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    var entity = await db.Products.FindAsync(key);
    if (entity == null)
    {
        return NotFound();
    }
    product.Patch(entity);
    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!ProductExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return Updated(entity);
}
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    if (key != update.Id)
    {
        return BadRequest();
    }
    db.Entry(update).State = EntityState.Modified;
    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!ProductExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return Updated(update);
}

Dalam kasus PATCH, pengontrol menggunakan jenis Delta<T> untuk melacak perubahan.

Menghapus entitas

Untuk memungkinkan klien menghapus produk dari database, tambahkan metode berikut ke ProductsController.

public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
    var product = await db.Products.FindAsync(key);
    if (product == null)
    {
        return NotFound();
    }
    db.Products.Remove(product);
    await db.SaveChangesAsync();
    return StatusCode(HttpStatusCode.NoContent);
}