Asp.NET Core Web API Uygulamasına OData Implementasyonu
Merhaba,
Bir önceki OData Nedir? GraphQL’den Farkı Nedir? başlıklı makalemizde OData’nın ne olduğundan ve muadili olan GraphQL’le arasındaki farkın neler olduğundan bahsetmiştik. Bu içeriğimizde ise pratiksel açıdan Asp.NET Core Web API uygulamalarına OData protokolünün nasıl implemente edilebileceğini ve böylece API’lara entity üzerinde sorgulama yeteneğinin kazandırılabilmesi için neler yapılması gerektiğini inceleyeceğiz.
OData bir protokoldür. Protokol; iki farklı sistemin birbiriyle nasıl haberleşeceğini belirleyen kurallar bütünüdür.
Implementasyon
OData’yı uygulamanıza entegre edebilmeniz için Microsoft.AspNetCore.OData kütüphanesini yüklemeniz yeterlidir.
Ardından ‘Startup.cs’ dosyasında aşağıdaki konfigürasyonların yapılması gerekmektedir.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
.
.
.
services.AddOData();
.
.
.
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
.
.
.
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Personel>("Personel");
builder.EntitySet<Kategori>("Kategori");
app.UseEndpoints(endpoints =>
{
endpoints.MapODataRoute("odata", "odata", builder.GetEdmModel());
});
.
.
.
}
}
Yukarıdaki kod bloğunu incelersek eğer; 8. satırda ‘AddOData’ metoduyla uygulamaya OData servisi eklenmektedir. 19 – 21. satırlarda ‘ODataConventionModelBuilder’ türünden nesne ile entitylerin nasıl sorgulanacağını bildireceğimiz bir convention tanımlıyoruz ve ‘EntitySet’ metotlarıyla belirtilen entitylere sorgulama yeteneğini kazandırmak için bildiride bulunuyoruz. Burada özellikle ‘EntitySet’ metodunun parametresine kullanılacak olan controller’ın ismini belirtmeye dikkat ediyoruz(Örn; ‘PersonelController’) 25. satırda ise ‘MapODataRoute’ metodu ile OData protokolüne uygun ‘www.example.com/odata/{controller}’ formatında bir rota oluşturuyoruz ve ‘GetEdmModel'(Edm : Entity Data Model) ile belirtilen entityler içerisindeki navigation propertyleri ve diğer tüm özellikleri oluşturulacak rotaya dahil ediyoruz.
‘Startup.cs’ dosyasında yapılan bu konfigürasyondan sonra istekleri karşılayacak olan controller’ları aşağıdaki gibi tanımlıyoruz.
public class KategoriController : ODataController
{
NorthwindContext _northwindContext;
public KategoriController(NorthwindContext northwindContext)
{
_northwindContext = northwindContext;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(_northwindContext.Kategoriler.ToList());
}
}
public class PersonelController : ODataController
{
NorthwindContext _northwindContext;
public PersonelController(NorthwindContext northwindContext)
{
_northwindContext = northwindContext;
}
[EnableQuery]
public IActionResult Get()
{
return Ok(_northwindContext.Personeller.ToList());
}
}
Örnek olarak ele aldığımız her iki controller’ı incelerseniz eğer ‘ApiController’ ve ‘Route’ attributeları kaldırılmış ve ‘ControllerBase’ yerine ‘ODataController’dan türetilmişlerdir. Bu şekilde tasarlanmalarının sebebi, artık tüm kontrolün OData üzerinde olmasından kaynaklanmaktadır. OData var olan katman üzerine yenisini ekleyerek, controller’lardaki sorumluluğu üstlenmektedir. Ayriyetten her iki controller içerisindeki ‘Get’ fonksiyonlarına göz atarsanız eğer ‘EnableQuery’ attribute’u ile işaretlenerek bu controller’ların ‘Startup.cs’ dosyasında tanımlanan entityleri üzerinden sorgulanma yetenekleri kazandırılmaktadır.
Test
Oluşturulan controller’lara normal istek gönderirsek eğer;

Görüldüğü üzere içerisinde birazdan değineceğimiz metadata bilgisini barındıran “@data.context” ile verileri barındıran “value” alanlarına sahip bir result oluşturularak, gönderilmektedir. Dolayısıyla burada OData üzerinden yapılan sorgulamalar neticesinde elde edilen verilerin ‘value’ alanından elde edileceğine dikkatinizi çekerim.
Tabi burada sonraki makalemizde detaylıca inceleyeceğimiz query option’lardan ‘$select’ parametresini kullanarak belirtilen alanların gelip gelmediğini de denetleyerek oluşturduğumuz yapılanmanın çalışmasını kontrol etmemizde fayda vardır.

Görüldüğü üzere url üzerinde https://localhost:5001/odata/ personel?$select=adi, soyadi şeklinde belirtilen bir query string ile kaynaktan gelecek olan verilerin sadece ‘adi’ ve ‘soyadi’ kolonlarının elde edilmesini bildirmiş bulunmaktayız.
Yapılan istek neticesinde OData protokolünün çalıştığını ve url üzerinden sorgulamanın başarılı bir şekilde gerçekleştiğini gözlemlemiş bulunmaktayız.
OData Metadata
Client, ‘Startup.cs’ dosyasında OData’ya set edilen entitylerin hangi propertylere sahip olduğunu görebilmek için metadata isteğinde bulunulabilmektedir. Bu istek neticesinde bir nevi servis dökümanları oluşturulacak ve client’a gönderilecektir. Bir url üzerinden metadata bilgilerini talep edebilmek için $metadata etiketinin kullanılması yeterli olacaktır.
Uygulamada Kullanılan Tüm Entityleri Sorgulamak
Uygulamada OData için set edilen tüm entitylerin metadata bilgilerine erişebilmek için /odata?$metadata url’ine istek gönderilmesi yeterli olacaktır.

Görüldüğü üzere uygulamada ‘Personel’ ve ‘Kategori’ olmak üzere iki adet entity’nin var olduğu bilgisi gelmekte ve böylece tüm entityler kullandığı url bilgisiyle birlikte listelenmektedir.
Entitylerin Propertylerini Sorgulamak
Mevcut entitylerin barındırdığı alanları sorgulamak için /odata/$metadata şeklinde istek gönderilmesi gerekmektedir.

Görüldüğü üzere istek neticesinde entitylerin propertyleri listelenmekte ve böylece client neye göre sorgulama yapacağını bilebilmektedir.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Gençay hocam, makale için teşekkürler. Yalnız benim kafama takılan bir soru oldu.
[EnableQuery] public IActionResult Get() { return Ok(_northwindContext.Personeller.ToList()); }kısmında tüm personeller database’den okunuyor ama filtremize göre mi ekrana return ediliyor? Yani tablomda 1 milyon satır varsa her istekte 1 milyon satır mı çekilecek yoksa kaçırdığım bir nokta mı var? sevgiler.
Merhaba,
Hayır, OData protokolü gelen request neticesinde işlevi manipüle edecek ve istendiği kadar veriyi database’den elde edip geri gönderecektir.