OData – Action/Function Yapılanması İle Custom Metot Oluşturma

Merhaba,

OData ile url üzerinden yapılan sorgulamayı karşılayacak actionları belirlerken belli kurallar çerçevesinde hareket etmekteyiz. Bu kuralların neler olduğunu OData Davranış Modellemesi ve Attributeları ve OData Custom Route Yapılanması başlıklı makalelerde detaylıca incelemiş bulunmaktayız. Bu içeriğimizde ise OData’nın bizlere sunduğu kuralları aşmamızı ve custom metotlar oluşturmamızı sağlayacak olan Action/Function yapılanmalarını inceliyor olacağız.

OData Action/Function Nedir?

Custom metot oluşturmamızı sağlayan yapılardır. Başlıktan da anlaşıldığı üzere Action ve Function olmak üzere ikiye ayrılmaktadırlar. Aralarındaki farkı anlayabilmek için Side Effect(Yan Etki) kavramına hakim olunması işimizi kolaylaştıracaktır.

Kısaca side effect; bir işlem yapılırken kapsamı dışındaki bir değişkenin, değerin veya objenin değiştirilmesi durumudur. Salt olarak OData ile ilgili bir kavram olmaktan ziyade dolaylı yoldan OData’yı da ilgilendiren bir anlama sahiptir. İşte bu kavramın ışığında Action ve Function yapılanmasını birbirlerinden ayırabilmekteyiz;

Action Function
Yan etkisi olan(side effect) OData operasyonları için kullanılır.

Genel olarak POST, PUT ve DELETE operasyonları işlevsel olarak yan etkiye sahip olduklarından dolayı Action olarak tanımlanmalıdırlar.

Ayrıca OData protokolü üzerinden complex type veri alış verişinde bulunulacaksa kesinlikle Action tercih edilmelidir.

Veri akışında gönderilen dataları ‘ODataActionParameters‘ türünden parametreyle yakalamaktadır.

Yan etkisi olmayan(no side effect) OData operasyonları için kullanılır. İdeal olarak yapılacak olan tüm GET işlemlerinde kullanılması tavsiye edilir.

Veri akışında gönderilen dataları ‘FromODataUri‘ attribute’u ile işaretlenmiş parametreyle yakalamaktadır.

Şimdi gelin sırasıyla her iki yapılanmayı pratikte inceleyelim;

Action Yapılanmasıyla Custom Metot Oluşturma

Action yapılanmasıyla oluşturulacak metotların temel ayırt edici özellikleri POST, PUT veya DELETE işlevlerine sahip olmasıdır. Dolayısıyla tüm bu işlevleri karşılayacak POST türünden istekler oluşturacaksanız action yapılanmasını tercih edebilirsiniz. Action yapılanması oluşturulacak custom metodun parametre alıp almamasına göre ikiye ayrılmaktadır;

Parametre Almayan Metot

Action ile parametre almayan metot geliştirebilmek için öncelikle ‘Startup.cs’ dosyasındaki ‘Configure’ metodu içerisinde aşağıdaki tanımlamanın yapılması gerekmektedir.

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            .
            .
            .
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Personel>("Personel");
            builder.EntitySet<Kategori>("Kategori");
            builder.EntitySet<Satis>("Satis");

            builder.EntityType<Personel>().Action("ToplamSatis")
                .Returns<int>();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapODataRoute("odata", "odata", builder.GetEdmModel());
                endpoints.OrderBy().Expand().Select().MaxTop(50).Count();
            });
            .
            .
            .
        }

11. satırdaki ‘EntityType’ fonksiyonuna göz atarsanız eğer ‘Personel’ entitysi ile ilişkilendirilmiş controller içerisinde, ‘Action’ metodu ile ‘ToplamSatis’ isminde geriye int türünden değer döndürecek bir custom metot bildiriminde bulunulmuştur.

    public class PersonelController : ODataController
    {
        .
        .
        .
        [HttpPost]
        public IActionResult ToplamSatis([FromODataUri] int key)
        {
            var personel = _northwindContext.Personeller.Include(p => p.Satislar).FirstOrDefault(p => p.PersonelId == key);
            return Ok(personel.Satislar.Count());
        }
    }

Bildirimde bulunulan metot ilgili controllerda ‘HttpPost’ attribute’u ile işaretlenerek tanımlanmıştır. Burada tanımlanan ‘int key’ parametresi aşağıda kullanılırken de göreceğiniz üzere metodun değil entitynin parametresidir.

Kullanımı
Tanımlanan bu custom metodu kullanabilmek için https://localhost:5001/odata/personel(1)/toplamsatis şeklinde bir url üzerinden sorgulama yapılması gerekmektedir. Buradaki tanımlamada ‘EntityType<Personel>’ metodu ile bir bildirim olduğundan dolayı ‘ToplamSatis’ metoduna ‘Personel’ entitysinin controllerı üzerinden erişilmek mecburiyetindedir. Dolayısıyla url’de mavi ile vurgulanan kısım ilgili controller’ı tarif etmektedir. Ayrıca ‘personel(1)‘ ifadesindeki id değeri yukarıda tanımlama yaparken bahsedildiği üzere oluşturulan custom metodun parametresi değil entitynin parametresini ifade etmektedir.
OData - Action/Function Yapılanması İle Custom Metot Oluşturma

Eğer ki entityde parametre almaksızın tüm entity nesneleri üzerinde işlem yapmak istiyorsanız aşağıdaki gibi bir bildirimde bulunmanız gerekmektedir;

            .
            .
            .
            builder.EntityType<Personel>()
                .Collection
                .Action("ToplamSatis")
                .Returns<int>();
            .
            .
            .

Burada dikkat ederseniz ”EntityType<Personel>’ metodundan sonra tüm koleksiyon verileri üzerinde çalışacağız anlamına gelen ‘Collection’ propertysi çağrılmakta, ardından ‘Action’ metoduyla operatif adımlara devam edilmektedir.

Hemen ardından bildirime uygun metodu ilgili controllerda tanımlayalım.

        .
        .
        .
        [HttpPost]
        public IActionResult ToplamSatis()
        {
            var personel = _northwindContext.Personeller.Include(p => p.Satislar).ToList();
            return Ok(personel.Sum(x => x.Satislar.Count));
        }
        .
        .
        .

İşte bu tarz bir metoda aşağıdaki gibi istekte bulunulması yeterli olacaktır.
https://localhost:5001/odata/personel/toplamsatis
Haliyle bu url üzerinden yapılan istekler örneğimize göre herhangi bir personelin değil tüm personellerin toplam satış adedini bizlere getirecektir.
OData - Action/Function Yapılanması İle Custom Metot Oluşturma

Parametre Alan Metot

Benzer mantıkla action yapılanmasıyla oluşturulan custom metoda aşağıdaki gibi parametrelerde tanımlanabilmektedir.

            .
            .
            .
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Personel>("Personel");
            builder.EntitySet<Kategori>("Kategori");
            builder.EntitySet<Satis>("Satis");

            var toplamSatis = builder.EntityType<Personel>()
                .Action("ToplamSatis")
                .Returns<int>();
            toplamSatis.Parameter<int>("nakliyeUcreti");
            toplamSatis.Parameter<string>("satisTarihi");
            .
            .
            .

Yukarıdaki kod bloğuna göz atarsanız eğer ‘nakliyeUcreti’ ve ‘satisTarihi’ olmak üzere iki adet parametre alan ve geriye int türünden değer döndüren ‘ToplamSatis’ isimli metot bildiriminde bulunulmuştur. Bu bildirim neticesinde ‘Personel’ controller’a gelip aşağıdaki gibi bir metot tanımlandığında;

        .
        .
        .
        [HttpPost]
        public IActionResult ToplamSatis([FromODataUri] int key, ODataActionParameters @params)
        {
            var satislar = _northwindContext.Satislar.Where(s => s.PersonelId == key && s.SatisTarihi.Value == DateTime.Parse(@params["satisTarihi"].ToString()) && s.NakliyeUcreti.Value >= int.Parse(@params["nakliyeUcreti"].ToString())).ToList();

            return Ok(satislar.Count());
        }
        .
        .
        .

https://localhost:5001/odata/personel(1)/toplamsatis url’i üzerinden istek yapılabilecektir. Metot bildiriminde tanımlanan ilgili parametrelerin değerleri url’e yapılacak POST neticesinde body üzerinden gönderilecektir ve bu değerler ‘ODataActionParameters’ türünden parametreyle yakalanacaktırlar.

Şöyle ki;
OData - Action/Function Yapılanması İle Custom Metot Oluşturma
OData - Action/Function Yapılanması İle Custom Metot Oluşturma

Burada önem arz eden bir hususa dikkatinizi çekmek istiyorum. Yukarıdaki gibi tanımladığınız parametrelerde tarihsel veriler için DateTime vs. gibi struct türler belirtmek yerine ‘string’ kullanmanızı tavsiye ederim. Aksi taktirde ‘ODataActionParameters’ parametresi değerleri yakalayamayacak ve null dönecektir.

Function Yapılanmasıyla Custom Metot Oluşturma

Function yapılanmasında ise action’a nazaran sadece ‘GET’ isteklerini karşılayacak metotların bildirilmesi tercih edilmelidir. Tıpkı action’da olduğu gibi parametre alan ve almayan olmak üzere ikiye ayrılmaktadır.

Parametre Almayan Metot

            .
            .
            .
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Personel>("Personel");
            builder.EntitySet<Kategori>("Kategori");
            builder.EntitySet<Satis>("Satis");

            builder.EntityType<Personel>()
               .Function("ToplamSatis")
               .Returns<int>();
            .
            .
            .

Görüldüğü üzere function ile custom metot bildiriminde actiondan tek farkı metot isminin ‘Function’ isimli metot içerisinde belirtilmesidir.

        .
        .
        .
        [HttpGet]
        public IActionResult ToplamSatis([FromODataUri] int key)
        {
            var satislar = _northwindContext.Satislar.Where(s => s.PersonelId == key).ToList();
            return Ok(satislar.Count());
        }
        .
        .
        .

Ayriyetten tanımlamada da ilgili metodun GET türünden olduğu bildirilmelidir. Bu işlem neticesinde https://localhost:5001/odata/personel(1)/toplamsatis şeklinde yapılacak GET isteği ilgili metodu tetikleyecektir. Burada ‘int key’ parametresi actiondakiyle birebir aynı mantıktadır ve yazdığımız custom metodun değil entitynin parametresidir. Eğer ki entity’de parametre tanımlamak istemiyorsanız actiondaki gibi ‘Collection’ propertysini kullanabilirsiniz.

            .
            .
            .
            builder.EntityType<Personel>()
               .Collection
               .Function("ToplamSatis")
               .Returns<int>();
            .
            .
            .

Parametre Alan Metot

Function ile tanımlanan custom metotlarda da parametreler actiondakiyle birebir aynı tanımlanabilmektedirler.

            .
            .
            .
            var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Personel>("Personel");
            builder.EntitySet<Kategori>("Kategori");
            builder.EntitySet<Satis>("Satis");

            var toplamSatis = builder.EntityType<Personel>()
                .Function("ToplamSatis")
                .Returns<int>();
            toplamSatis.Parameter<int>("nakliyeUcreti");
            toplamSatis.Parameter<string>("satisTarihi");
            .
            .
            .

Lakin parametre değerlerini yakalayabilmek için aşağıdaki gibi ‘FromODataUri’ attribute’u ile işaretlenmiş fiziksel parametrelerin ilgili metot imzasında tanımlanması gerekmektedir.

        .
        .
        .
        [HttpGet]
        public IActionResult ToplamSatis([FromODataUri] int key, [FromODataUri] int nakliyeUcreti, [FromODataUri] string satisTarihi)
        {
            var satislar = _northwindContext.Satislar.Where(s => s.PersonelId == key && s.SatisTarihi.Value == DateTime.Parse(satisTarihi) && s.NakliyeUcreti.Value >= nakliyeUcreti).ToList();
            return Ok(satislar.Count());
        }
        .
        .
        .

Bu şekilde function yapılanması ile oluşturulan metotları tetikleyebilmek için
https://localhost:5001/odata/personel(1)/toplamsatis(nakliyeUcreti=10, satisTarihi='1997-01-01 00:00:00.000') şeklinde bir url kullanılması gerekmektedir.

OData - Action/Function Yapılanması İle Custom Metot Oluşturma

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

2 Cevaplar

  1. 27 Mayıs 2020

    […] önceki OData – Action/Function Yapılanması İle Custom Metot Oluşturma başlıklı makalemizde OData protokolünde varsayılan kuralları aşmamızı sağlayan custom […]

  2. 27 Mayıs 2020

    […] OData – Action/Function Yapılanması İle Custom Metot Oluşturma […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*