Caner Tosuner

Leave your code better than you found it

Web Api Projesi Oluşturma

Şöyle bir örnek proje yapalım. TodoApi adında bir WebApi projemiz olsun ve bu Api'a bir tane controller tanımlayıp içerisine TodoList dönen bir metot yazalım.

İlk olarak Visual Studio açıyoruz ve File => New => Project diyoruz ve aşağıdaki görselde olduğu gibi Web kategorisine tıklayıp sonrada ASP.Net Web Application'ı seçiyoruz ve projenize bir isim verdikten sonra OK'e tıklıyoruz.

 

Daha sonra açılam ekrandan Empty kategorisini tıklayıp ekranın orta kısmında bulunan checkbox'lardan WebApi'ı seçiyoruz ve OK'e tıklıyoruz.

 

Artık solution'da projemiz hazır. Şimdi ilk olarak Models klasörü içerisine TodoItem isminde aşağıdaki gibi bir class tanımlayalım.

namespace TodoApi.Models
{
    public class TodoItem
    {
        public string Key { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

Şimdi ise TodoController adında controller'ımızı tanımlayalım. Bunun için solution'da bulunan Controller klasörünün üzerine gelip sağ tıklayıp Add diyelim sonrasında açılan ekrandan Controller'ı seçelim ve Controller'a TodoController ismini verip OK'e tıklayalım.

Artık TodoController'ınıda oluşturduk şimdi sırada GetAllTodoItems isminde HTTPGET request'i atılabilen ve geriye List<TodoItem> dönen bir metot yazalım.

public class TodoController : ApiController
    {
        [HttpGet]
        public List<TodoItem> GetAllTodoItems()
        {
            var responseList = new List<TodoItem>
            {
                new TodoItem{
                    Key="SD2",
                    Name="Görev1",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD11",
                    Name="Görev2",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD251",
                    Name="Görev3",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD8",
                    Name="Görev4",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD01",
                    Name="Görev5",
                    IsComplete=true,
                },
                new TodoItem{
                    Key="SD42",
                    Name="Görev6",
                    IsComplete=true,
                },
            };

            return responseList;
        }

Api projemiz var. Şimdi gelin bu Api'a requestte bulunup ne response dönüyor onu görelim. Projeyi çalıştıralım ve her hangi bir rest client tool kullanarak aşağıdaki link'e requestte bulunalım.

  • http://localhost/api/Todo/GetAllTodoItems

Ben genelde Postman'i kullanıyorum ve aşağıdaki gibi Postman ile GET request'i atıyoruz.

 

Dönen response'a baktığımızda aşağıdaki gibi json formatında response geldiğini göreceğiz.

 

WebApi candır arkadaşlar ve servis tarafında geliştirme yapıyorsanız da çok ama çok önemlidir. Bir Microsoft yetkilisi bir konferansta şuna benzer bir cümle kurdu "Biz daha iyisini yapana kadar en iyisi bu !".

 

Web Api Projesine Cache Ekleme - OutPutCache

Server-side tarafında geliştirme yapan arkadaşlar bilirler ki request-response time ları çok büyük önem sarf etmektedir. Örnek olarak, bir muhasebe DB niz var ve her gün gece 23:59 da günlük raporlar giriliyor veya 3 dkka yeni kayıt girilen bir yapıda olabilir. İlgili tabloda şuana kadar 200 bin kayıt girilmiş diyelim. select * from Raporlar dediniz ve size 200 bin kayıtı ortalama 15 sn de getirdi (DB nin serve edildiği Pc nin özellikleri ve network hızı gibi çeşitli etkenlere göre değişir). Aslında bu gibi yapılarda ilgili  StoraProcedure e paging parametreleri vererek daha performanslı ve hızlı bir sorgu yazabiliriz ancak bu durum için bile Cache yapısını uygulamamıza entegre edebiliriz. Şimdi bu raporları feed eden bir mobil uygulamamız, Web Sayfanız veya bir masaüstü uygulamanız olabilir ve iş ilgili uygulamanın kullanım oranına göre dakikada 100-200 request te bulunuyor olabilirsiniz. Bu uygulamalara db ile connection'ı sağlayan bir Web Api uygulamamız olsun. Şimdi yukarıda ki case de uygulamada bulunan RaporlarController 'ına dakikada 100-200 arası istek bulunmakta. Ne yapacağız peki sürekli olarak DB ye git select * from Raporlar deyip 200 bin kayıtı almak için 15 sn sürsün network vs işlemlerinden dolayı 2 sn de ordan olsun artı birde kullanıcının internet hızı kotalımı dersin :) ttnet sağolsun hızı düşürmüş 2 mb'e ve oda yaklaşık olarak 5 sn sürsün diyelim (değerler tamamiyle dummy dir). Şimdi küçük bir matematik işlemiyle ortalama kaç sn de veriyi getiriyoruz;

DB QueryResult : 15 sn

WebApi projesinin Download Süresi : 2 sn

Client uygulamasının Download Süresi : 5 sn

Client uygulamasının bu veriyi ekrana çizmeside yaklaşık 2 sn diyelim (Performanslı cihazlarda)

int[] arr = { 15 , 2, 5, 2 };
 
int sumResult = arr.Sum();
Console.WriteLine(sumResult); 
24 saniye 

Adama "Oh My God" dediğinde "Yes your god" diye cevap verirler. 

Tamı tamına 24 saniye  (biraz abartmışta olabiliriz ). Günde ortalama 100 kişinin kullandığını düşündüğümüzde her gelen 24 sn beklicek. Böyle bir projeyi al çöpe at derler adama. Benzer bir olay daha önce çalıştığım bir şirkette başıma geldi ve page_load da db ye gidip 4.600.000 kayıt için sorgu atılıyordu ve bazı işlemler yapılmaya çalışılıyordu. Projeyi bana assign edip müşteri sayfayı açamıyormuş bi bakarmısın dediler ve sorunu anladığımda yazılımdan soğmuştum diyebilirim. 

Her neyse gelelim konumuza. Projeyi bu halde bırakmayalım ama çöpede atmayalım. Projemize sağ tıklayıp nugetten WebApi OutPutCache.Core ve OutPutCache.v2 dll lerini ekleyelim.

Senaryomuz şu şekilde olacak;

1-Controller bazında hem server side için hemde client için iki tarafta da cache sağlayacak bir yapı yapıyoruz. Kullanacağımız kütüphaneye 2 parametre vericez  ServerTimeSpan  ve ClientTimeSpan .  Biri ServerSide için cache'i sağlicak yani kendine gelen ilk request'in response'ını alıp set edilen süre boyunca aynı requestle başka bir kullanıcı geldiğinde cache den alıp o yeni gelen kullanıcıya verecek. Diğeri ise ClientSide için clienta dönen response'un header'ına Cache-Control →max-age=60 eklicek. Bu şu anlama geliyor; Client'a diyor ki arkadaş ben bu respons'u 60 sn cache ledim ve sende istersen gelen response'u biyerde tutup bana 60 sn boyunca gelmeyebilirsin. 60  sn sonra tekrardan gel. Şimdi gelelim code tarafına ilk olarak WebApiCacheAttribute adında CacheOutputAttribute inherıt olan bir attribute tanımlıyoruz. Alında direkt olarak CacheOutputAttribute  controllerımızın içerisindeki metodların başına ekleyebilirdik ancak yönetimi daha kolay olur düşüncesiyle araya işimi daha kolaylaştıran WebApiCacheAttribute  adında CustomAttribute ünü yazdım.

public class WebApiCacheAttribute : CacheOutputAttribute
    {
        public ApiCacheAttribute()
            : this(WebConfigApiClientCacheDuration,WEebConfigApiServerCacheDuration){ }

          public ApiCacheAttribute(int clientCacheDuration = 0,
                                 int serverCacheDuration = 0)
        {
            base.ServerTimeSpan = serverCacheDuration;
            base.ClientTimeSpan = clientCacheDuration;
        }
    }

Üstte görüldüğü gibi bu Cache attribute'ü 2 parametre alıyor. Bu parametreleri attribute implementasyon sırasında aşağıda olduğu gibi biz değer atamaz isek WebConfig dosyasında tanımlı olan değerli alarak Cache sürelerini set ediyor.

WebConfig de appsettings de kayıtlı olan değerleri okuyarak cache işlemini yapar

[WebApiCacheAttribute]
public IHttpActionResult GetItems()
{
      var products= new IkiYuzBinKayit(); //db den 200 bin kayit getirmişiz varsayalım
      return Ok(product);
}

Ama istersek aşağıda olduğu gibi bizde bu değerleri set edebiliriz

[WebApiCacheAttribute(ApiServerCacheDuration=120,ClientCacheDuration=120)]
public IHttpActionResult GetItems()
{
     var products= new IkiYuzBinKayit(); //db den 200 bin kayit getirmişiz varsayalım
     return Ok(product);
}
 

Sonuç olarak web api projemizde cache attribute eklediğimiz metoda yapılan sorgular set edilen sürelere göre cache lenir ve o süre boyunca aynı parametrelerle gelen bütün kullanıcılara cachelenmiş olan response döner. Süreç server cache süresi bittiğinde sonlanır ve yeniden gelecek olan ilk sorgu beklenir ve döngü şeklinde devam eder.

 

Not ! Cache Cache'dir ancak hangi datanın cachelenip cachelenmemesi konusu çok ama çok önemlidir !! İyice düşünüp karar verilmesi gereken bir konudur.

Asp .Net Web Api Nedir

Daha önceki yazılarımızda Web Api dedik, Cache dedik, Exception Handling dedik ama Web Api nedir bir türlü bahsedemedik. Bu yazımızda kısaca Api & Asp.Net Web Api nedir konuşuyor olacağız.

Api Nedir ?

Asp .Net Web Api'a geçmeden önce Api nedir ondan bahsedelim. Aoi açılımı "Application Programming Interface" olan Türkçe'de uygulama geliştirme arayüzü anlamına gelir ve sahip olduğumuz service veya verileri dış dünyaya açıp başka uygulamaların-platformların kullanımına sunmak için belli kurallar çerçevesinde tanımlamalar yaptığımız arayüz dür. 

 

Asp .Net Web Api Nedir ?

Microsoft yetkilileri Web Api sunumlarından birinde şuna benzer bir şey söyledi "Biz daha iyisini yapana kadar en iyisi bu..!"

Asp .Net Web Api ise farklı türde sayısız client (browsers, mobile phones, tablets, pc, etc.) tarafından consume edilebilen HTTP protokolü üzerinden haberleşebilen servisler oluşturmak için kullanılan bir framework şeklinde tanımlayabiliriz. Asp .net MVC ile routing, controllers, action results, filter, model binders gibi ortak feature'lara sahip olduklarından bir takım benzerlikler göstermektedir ancak MVC Framework'ün bir parçası değildir. Asp .net Web Api Core Asp .Net'in bir parçasıdır ve MVC veya diğer web application türleri ile birlikte kullanılabilir. Aynı zamanda bütün bunlardan bağımsız stand-alone Web services application olarakta kullanılabilir. 

 

Neden Asp.Net We Api ?

Günümüz dünyasında teknolojini gelişmesiyle birlikte firmalar artık web tabanlı uygulamalar üzerinden müşterilerine tam olarak ulaşamaz hale geldiler. İnsanlar artık günlük hayatlarının nerdeyse %50 sini akıllı telefonlar, tablet pc vs ile geçiriyorlar ve bu cihazlarda insanların hayatlarını kolaylaştıracak olan milyonlarca uygulama mevcut. Bunların yanında birde İOT ile birlikte gelecek 5 yılda dünyada 30 milyara yakın internete bağlanabilen cihazlar olacağından bahsediliyor ve buda belki milyonlarca Api geliştirmesi demek.

Firmalar veya uygulama geliştiriciler müşterilere daha kolay ve hızlı bir şekilde ulaşmada kullanmak için servislerini ve sahip oldukları verilerin bir kısmını browserlar yada internete bağlanabilen bu akıllı cihazlar tarafından consume edilebilmeleri için Api'lar geliştirmeleri gerekmektedir. Çünkü Api'lar yapısı gereği bütün programlama dilleri tarafından ortak kabul görmüş medya tiplerini (XML-JOSN..etc.) response olarak alıp gerekli parse işlemlerinden sonra kolayca kullanabilir. 

 

Web Api sahip olduğunuz veri ve servisleri birçok farklı cihazda kullanıma sunmak için expose edebilmenizi sağlayan şahane bir framework ve dahası Web Api .Net Framework üzerinde RESTful servisler inşa etmenizi sağlayacak ideal bir open source platform. WCF Rest service'lerinin aksine Web Api HTTP protokolünün bütün özelliklerini kullanır (URIs, request/response headers, caching, versioning, çeşitli content format'ları) WCF Rest Service'lerinde yapıldığı gibi farklı cihazlar için extra config ayarları vs yapmamıza da gerek bulunmamaktadır. Request'i yapılırken dönmesi gereken response'un XML mi yoksa JSON formatında mı olacağına client'ın seçimine bırakılmıştır çünkü Web Api birden fazla medya formatında response dönebilmektedir.

 

Başlıca Web API Özellikleri

  • Http Get, Post, Put ve Delete metodlarıyla çalışabildiğinden CRUD işlemelrini destekler,
  • Response'larda HttpStatusCode ve Accept Header parametreleri bulunur,
  • Response'lar kullanıcının istediği türde MediaTypeFormatter tarafından formatlanabilir,
  • OData desteği bulunmaktadır ve Query yazması oldukça kolaydır,
  • Bir uygulama içerisinde veya IIS üzerinde host edilebilir,
  • MVC'nin bazı özelliklerini taşır (routing, controllers, action results, filter, model binders)

 

Neden Web Api'ı Seçmeliyiz ?

  • Bir web service'e ihtiyacınız varsa ve soap'a ihtiyacınız yoksa en iyi seçenek Web Api dir,
  • Geliştirme sürece WCF de olduğu kadar zahmetli ve sıkıntılı değildir,
  • Http tabanlı olduğundan Rest-ful servisler geliştirmek için en iyi seçenektir,
  • Exception ve Cache mimarileri oldukça performanslı ve yönetilebilir dir,
  • Open Source olduğundan sürekli olarak geliştirilip yeni feature'lar eklenmektedir,
  • Microsoft yetkilileri Web Api sunumlarından birinde şuna benzer bir şey söyledi "Biz daha iyisini yapana kadar en iyisi bu..!" bu demek oluyor ki tam destek.

yield nedir nasıl kullanılır

Bilineceği üzere bir class ın foreach iterasyonuna sahip olabilmesi için IEnumerable interfacesini implement etmesi gerekmekte. IEnumerable 'ı implemente eden class bu implementle birlikte override edilmesi gereken GetEnumerator metoduna sahip olur ve bu metodun içerisini doldurduktan sonra artik bu class da foreach ile gezebilecek duruma gelir. GetEnumerator metodunu override ederken, MoveNext(), Reset() metotlarini ve Current isimli propertyleri ile ilgili logic'i handle etmemiz gerekiyordu. İşte yield sayesinde bunları yapmaktan kurtuluyoruz. 

Mantigi oldukca basit ama bazi projelerde uygulamaya entegrasyonu sıkıntı çıkarabiliyor. Iste bu  sıkıntıları gidermek için C# 2.0 ile birlikte gelen yield keywordu sayesinde bu işlemlerin tumu bizim için arka planda yapilmis olacak.

Senaryomuz şu şekilde olsun; geriye db de kayıtlı olan ürünleri dönen bir metodumuz var ve bu metodu yield kullanmadan ve yield kullanarak yazmaya çalışalım.

Yield kullanmadan

     public static IEnumerable<Product> GetAllProducts()
            {
                using (var db = new DbEntity())
                {
                    var productList = from product in db.Product
                                      select product;
                    return productList.ToList();
                }
            }

 

Bu normal şartlarda kullandığımız yöntem. İlgile metodu aşağıdaki gibi çağırıp dönen listeye direk olarak erişebilirsiniz.

var productList = GetAllProducts();

yield kullanarak ise şu şekilde yazabiliriz 

Yield Kullanarak

public static IEnumerable<Product> GetAllProducts()
            {
                using (var db = new DbEntity())
                {
                    var productList = from product in db.Product
                                   select product;
                    foreach (var item in productList)
                    {
                        yield return product;
                    }
                }
            }

yield da ise şu şekilde çalışır;

döngüye her girdiğinde yield return product satırında fonksiyonun çağrıldığı yere ilgili product item'ını döner yani return'ü gördü diye foreach den ve metoddan direkt çıkmaz ve listenin içindeki tüm elemanlar bitinceye kadar bu işlemi yapmaya devam eder.

IL Disassambler(ILDASM) acarak code tarafında MoveNext,Reset ve Current gibi uyeler yazmamamiza ragmen yield keywordu sayesinde arka planda bunlarin yazildigini goruyoruz.

 Bir diğer örnek olarak ise şunu verebiliriz; 

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 45;
}

Foreach de dönerken her bir int i için IEnumerable<int> Integers() metoduna giderek değerleri bize teker teker döndürebiliyor.