Bu makalede Web API ve SQL Server kullanarak örnek veritabanı
Northwind üzerinden bir uygulama yapacağız. Bir Model ve Controller
kısmımız olacak. View’i ise client olarak düşünebiliriz. Amacımız bir
kategoriler controller’ı ile kategorileri görüntülemek olacak.
Web API nedir?
Web API
bir web servisi teknolojisi,
RESTFull
bir servisdir.
ASP.net
ise Microsoft’un ürettiği bir web geliştirme platformudur.
İçerisinde bir
MVC
yapısı barındırmaktadır.
Web API
teknolojisini kullanarak kullanıcıyla anında iletişime geçebilen
Real-Time
applicationlar yapabilabilir.
SOA, SOAP ve RESTFull
SOA
benzetecek olursak
Object Oriented
gibi bir yazılım geliştirme yaklaşımıdır.
Service Oriented Architecture
olarak kısalttığımız bu yapı bildiğimiz web servisleri içeriyor.
Bu yapının altında
SOAP
ve
Restfull
dediğimiz yapılar var.
Gerekli yapıların birbiriyle entegrasyonunu sağlamak için kullanılıyor.
Basit bir şekilde şöyle düşünebiliriz: Projelerde kullandığımız çok
katmanlı mimaride business logic katmanı ile data layer’ı ayrı bir proje
yaparak bunu web ortamında sunuyoruz.
Client tarafı ise bunlardan bağımsız oluyor. Sonuç olarak client ve web servis tarafını birbirinden ayırıyoruz.
SOAP – Simple Access Object Protocol – Bu yapının belli başlı standartları var.
Güvenlik, performans. WCF .net tarafında kullanılıyor. Tamamen bir XML çıktısı üretiyor.
Bu XML ise aslında envelop tagleri arasında bir header ve body nin bulunduğu bir yapı.
Bununla belli başlı uygulamaları haberleştirebiliyoruz.
Restfull ise daha sonra ortaya çıkan bir teknoloji. Temsili durum
transferi (representational state transfer) anlamına geliyor. Çok esnek
ve rahat tamamen HTTP protokolüne odaklı. SOAP’da TCP HTTP tercihi
yapabilirken burada tamamen HTTP üzerindeyim bunun artısı da web
üzerinde çok rahat bir şekilde Web API tarafında kullanabileceğim bir
yapı olması oluyor.
Restfull servislerin döndürdüğü veri tipi konusunda katı kuralları
yok. İstenilen formatta geri dönüş sağlayabiliyor. Güvenlik anlamında
ise birez zayıf o yüzden kendi güvenlik yapılarımızı inşa etmemiz
gerekebiliyor. Günümüz teknolojilerinde bunun da daha rahat yolları var.
Servis mimarilerinde kritik nokta platform bağımsız biçimde
çalışabilmek. Dönen json data Java’da,PHP’de, .Net de okunabiliyor. JSON
web ortamında hızlı javascript’e entegre. Performans açısından boyut
çok önemli.
XML:
JSON:
- Burada
name
etiketi XML’de iki defa kullanılırken JSON gösteriminde bir defa kullanılıyor dikkat ederseniz.
- Mobil burada bir diğer kritik noktayı oluşturuyor. Çoğu mobil
uygulama servisle haberleşmek durumunda. Servis kullanıldığında Android,
iOS olması fark etmiyor.
Her işimizi JSON objeleriyle görebiliyoruz.
- Web API performans olarak avantajları arasında
caching
ve asenkron yapılar
yine söz konusu.
- JSON kullanımına şöyle bir örnek verilebilir: ASP.net 4’de config
yapısı XML formatındadır. Artık ASP.net 5’de bu bile JSON’a döndü.
- Biz de projemiz içerisinde veritabanından çektiğimiz verileri JSON
formatında dışarıya servisle açıp yine dışarıdan gelen JSON objelerini
database’imize kaydedeceğiz.
- Proje içerisinde
NORTHWND
veritabanını kullanacağız. SQL Server
ve Northwind
veritabanının hazır olması gerekiyor.
Management Studio
ile veritabanımızı bir kontrol edelim. Daha sonra bu kısımda sıkıntı yaşamak istemiyoruz çünkü.
- Örneğin servisin aşağıdaki gibi açık olması gerekiyor.
Projenin Oluşturulması
File > New > Project
diyerek projemizi oluşturmaya başlayalım. Web altında ASP.NET Web Application
seçip isim veriyorum.
Empty Template
altından Web API
‘ı açıyorum. Özellikle öğrenirken boş template üzerinden gitmek daha faydalıdır.
- Bir MVC projesi açıldığında bunun bir tarafında da bir web servisi
de host edilebilir. Ama bu çok ihtiyacımız olan bir yapı olmuyor. Ama
böyle bir imkan var ihtiyaç olursa.
Solution Explorer
‘da gördüğünüz gibi MVC’den alışkın olduğumuz Model
‘lar Controller
‘lar var ama gördüğünüz gibi bir View
yok. View kısmı client olarak düşünülebiliriz.
- Models içerisine Orm ve Dto klasörleri oluşturalım. Entity Framework
yapısını Orm klasörünün içerisinde, Data Transfer Objelerimiz olacak
Dto’ları da Dto klasörü içerisinde saklayacağız.
Database ve ORM
- Orm içerisine
Add>New Item
diyerek Data
sekmesi altında ADO.net Data Entity Model
ekleyelim. Northwind
örnek database’i ile çalışacağız.
- Gelen pencerede
EF Designer from database
seçili direk Next
diyoruz. New Connection
dedik.
- Server Name kısmına
.
yazıp Windows Authentication
‘u seçelim. Database olarak NORTHWND
‘ı seçip onaylayalım.
Entity Framework 6.x
versiyonunu kullanıyoruz. Yalnızca Tables
diyerek tabloları ekleyelim.
- İşlem tamamlandığında database bağlantısı gerçekleştirilip gerekli
ORM yapısı kurulmuş oldu. Artık kodumuzu yazmaya başlayabiliriz.
Controllers Sınıfı
- Controllers klasörü içerisine yine
Add>New Item
diyerek bir Web API 2 Controller - Empty
controller oluşturalım.
- Bu controller kategorileri döndürecek. İsim olarak
CategoryController
verelim. Namespace tanımlamaları altında karşımıza gelen böyle bir yapı oldu:
|
//...
namespace _1110_WebApi.Controllers
{
public class CategoryController : ApiController
{
}
}
|
- Bunun bir Web Api olmasını sağlayan ApiController class’ının içerisindeki yapılar.
- Entity’den instance alalım öncelikle.
Web.config
içerisinde <connectionstrings>
altında <add name="NORTHWNDEntities"...
ile NORTHWNDEntities
olarak gözüküyor. Namespace’imizi ekliyoruz.
1
2
3
4
5
6
7
8
9
10
11
12
|
using _1110_WebApi.Models.Orm;
// ...
namespace _1110_WebApi.Controllers
{
public class CategoryController : ApiController
{
NORTHWNDEntities db = new NORTHWNDEntities();
}
}
Bu controller’a kategoriler için gerekli işlemleri yapacak metodları
yazacağız. Kategorileri getirmek ile başlayalım. Fakat kategorileri
getirecek metodu tanımlamadan önce yapmamız gereken bir şey var.
DTO – Data Transfer Objesi
- Bir servis kullanıyorsak gerek güvenlik gerekse performans anlamında
bir data transfer objesi kullanmalıyız. Örneğin Product class’ına
baktığımız zaman çok sayıda property’si olduğunu görüyoruz. Şimdi bu
noktada bir servisi dışarıya açarken ben hepsini birden dışarıya açmak
istemeyebiliriz. Bu güvenlik açısından işimize gelmeyebilir. Karşı
tarafın buna ihtiyacı olmayabilir. Sunucumuzun performansını buna
harcamak istemeyebiliriz. Bu noktada da ben bu değerleri bir transfer
objesi üzerinden bunları dışarıya açacağız.
- Bunun için
Dto klasörünün içerisine CategoryModel isimli bir class oluşturalım. İçerisine aşağıdaki gibi gerekli propertyleri giriyorum.
prop yazıp iki kere tab tuşuna basarsanız daha hızlı eklemeniz mümkündür. Visual Studio içerisinde bunlara snippet denir. ctrl+k ctrl+x yaparak diğer snippetleri görebilirsiniz.
|
// ...
namespace _1110_WebApi.Models.Dto
{
public class CategoryModel
{
public string KategoriAdi { get; set; }
public string Aciklamasi { get; set; }
}
}
|
- Ne yaptık?
CategoryModel adında bir Dto ve iki adet
property’sini oluşturduk. Şimdi artık dışarıya açacağımız Model’in
tipini CategoryModel olarak seçeceğiz.
- ORM’nin içerisindeki Category class’ı üzerinden değil de CategoryModel class’ı üzerinden veri çıkışını gerçekleştireceğiz.
- Artık Controller içerisine geri dönebiliriz. CategoryModel’leri barındıran bir list döndürecek aşağıdaki fonksiyonu oluşturalım.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
using _1110_WebApi.Models.Dto;
using _1110_WebApi.Models.Orm;
// ...
namespace _1110_WebApi.Controllers
{
public class CategoryController : ApiController
{
NORTHWNDEntities db = new NORTHWNDEntities();
public List<CategoryModel> GetAllCategories()
{
List<CategoryModel> catList = db.Categories.Select(x => new CategoryModel()
{
KategoriAdi = x.CategoryName,
Aciklamasi = x.Description
}).ToList();
return catList;
}
}
}
|
- Yukarıdaki tanımlanan
GetAllCategories bütün kategorileri döndüren bir metod.
- Bu metod içerisine
List<CategoryModel> catlist = db.Categories.ToList(); dersek db.Categories.ToList() ile bütün kategorileri döndürmüş oluyoruz.
- Bunun yerine
ToList() demeden önce buna bir select yaparak CategoryModel tipinde bu listeyi çekeceğiz.
- İçerisinde DTO’nun
KategoriAdi ve Aciklamasi propertylerini databaseden gelen CategoryName ve Description kategorilerine eşleyeceğiz.
- Bu liste artık bana
KategoriAdi ve Aciklamasi databaseden gelen değerlerle dolu bir liste halinde sunulacak.
- Bu listeyi de return edeceğiz.
XML Yerine JSON ve Route Ayarları
- Bu aşamada projeyi
Build edip çalıştırdığımızda karşımıza çıkan sayfada HTTP Error 403.14 - Forbidden hatası alıyoruz.
- Fakat
/api/category dediğimiz takdirde xml formatında database’imdeki bütün kategorileri dışarıya açmış oldum.
- Peki burada iki action olsa ne olacaktı? Category altında birden fazla fonksiyon da olabilir.
- Bu noktada da
App_Start altında WebApiConfig.cs içerisinden yapacağımız rootconfig yapılandırması ile beraber action adını da istiyoruz.
WebApiConfig.cs içerisinde routeTemplate: "api/{controller}/{id}", satırını routeTemplate: "api/{controller}/{action}/{id}", ile değiştirelim.
- Artık action adı olan
GetAllCategories ‘i de URL’e eklememiz gerekecek.
/api/category/GetAllCategories dediğimizde yine önceki değerleri görüntülebiliyoruz.
- Bu noktada az önceki gibi bütün kategorilere rahatlıkla
erişebiliyorum ve daha sonra yazacağım ikinci bir metoda da rahatlıkla
erişebileceğim.
- XML yerine JSON döndürmek için yine aynı dosyada
// Web API configuration and services diye belirtilmiş kısmın altında,
|
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
|
Yukarıdaki satırı ekleyerek default olarak belirtilen XML yapısını temizlediğim takdirde bu sefer bana JSON döndürecektir.
- Eğer id’sine göre tek bir kategori döndürmek istiyorsak
GetAllCategories dışında yeni bir metod tanımlamamız gerekiyor.
- Bunun için
CategoryController.cs dosyamızı açalım. GetAllCategories den sonrasına GetCategoryByID fonksiyonu tanımlayalım.
- Yeni fonksiyonumuz tek bir kategori döndüreceğinden bildirilmesi
public CategoryModel GetCategoryByID(int id) şeklinde olacak.
- Dışarıdan da parametre olarak
id alıyor.
- Dışarıdan aldığımız bu idye göre de database’den de o id’li kategoriyi yakalayacağız.
|
public CategoryModel GetCategoryByID(int id)
{
Categories cat = db.Categories.Find(id);
//...
}
|
Peki bu id nasıl gelecek? Hatırlarsanız WebApiConfig içerisindeki default yapılandırmada bir id vardı:
|
routeTemplate: "api/{controller}/{action}/{id}",
|
Buradaki id sayesinde bu id atanacak.
|
public CategoryModel GetCategoryByID(int id)
{
Categories cat = db.Categories.Find(id);
CategoryModel catModel = new CategoryModel();
catModel.Aciklamasi = cat.Description;
catModel.KategoriAdi = cat.CategoryName;
return catModel;
}
|
- Artık
/api/category/getCategoryByID/2 diyerek id’si 2 olan kategoriyi döndürebilirim.
- Burada önemli bir nokta metodun adının başındaki
Get ‘in request’in tipini belirten bir anahtar kelime olmasıdır.
- O
Get i sileresek metodun get requesti olduğu anlaşılmaz. Örneğin metodu CategoryByID olarak değiştirirsek çalışmayacaktır:
|
{"Message":"The requested resource does not support http method 'GET'."}
|
- Bundan kaçınmanın bir diğer yolu ise metodun başında tipini belirtmektir:
|
[HttpGet]
public CategoryModel CategoryByID(int id)
{
Categories cat = db.Categories.Find(id);
CategoryModel catModel = new CategoryModel();
catModel.Aciklamasi = cat.Description;
catModel.KategoriAdi = cat.CategoryName;
return catModel;
}
|
- Bu şekilde yazdığımızda metodun isminin başında
Get yazmasa da çalışacaktır.
- Özel bir neden yoksa ilk seferdeki gibi metodun isminde belirtmek daha doğru olacaktır.
- Fiddler, Postman gibi toollarla GET requesti gönderip sonucu inceleyebiliriz.
- 200 status kodu isteğin (request) başarılı olduğu anlamına gelir.
- Yukarıda response’u yani sunucunun verdiği cevabı ham haliyle görebiliyoruz. İlk satır status code bilgisi, altındakilerin ise
HTTP headerları olduğunu görüyoruz.
Bu bilgiler gelen verinin künyesi gibi düşünülebilir.
POST Metodu ile Database Insert İşlemi
- Bu noktaya kadar yalnızca
GET metodlarıyla çalıştık. Ama HTTP yalnızca GET metodlarıyla sınırlı değil.
POST metodu ile gönderdiğimiz veriyi database’imize kaydetmeyi deneyelim.
Northwind içerisinde categories tablosuna bakacak olursak:
- Bu tablo içerisine kategori ekleyeceğiz. Öncelikle
CategoryController.cs dosyamıza bir POST metodu yazalım.
- Metodun dönüş tipi
IHttpActionResult olacak. Bu tamamen arkada asenkron çalışan bir yapıya sahip bir action result tipi.
- Metodun ismini
AddCategory yapalım. Adında bir POST anahtar kelimesi kullanmadığım için attribute olarak üstünde bunun bir POST metodu olduğunu belirtmeliyiz.
|
//...
[HttpPost]
public IHttpActionResult AddCategory()
{
//...
}
|
İçerisine yazacağımız return statement’da ise return Json(""); gibi bir dönüş yapabiliriz.
Ama bundan ziyade return Ok(); diyebiliriz. Burada ok dediğimiz 200 status kodlu herşey yolunda cevabı oluyor.
Buradan benzer şekilde birçok HTTP word’ünü – NotFound() veya BadRequest() gibi- döndürmek mümkündür.
Fonksiyonumuza parametre olarak ise Dto’da belirttiğimiz CategoryModel tipinde bir nesne veriyoruz.
|
//...
[HttpPost]
public IHttpActionResult AddCategory(CategoryModel _model)
{
//...
return Ok();
}
|
İçerisinde database ile bağlantı kurulacak bölümü yazmadan önce nesnenin dolu geldiğini görüyor olmam gerekiyor.
Debug modunda fonksiyona breakpoint koyup çalıştırdıktan sonra. Fiddler veya Postman’den aşağıdaki adrese altındaki içeriği gönderelim.
|
/api/category/AddCategory
{
"Aciklamasi":"Cat123",
"KategoriAdi":"Descrip123"
}
|
Request’i gerçekleştirirken Content-Type:application/json header’ını da belirtmemiz gerekiyor.
İlgili url’e bir request gerçekleştiğinde uygulamamız bunu yakalayacak.
- Yukarıda request ile gönderilen verinin başarıyla obje içerisine geçmiş olduğunu görüyoruz.
- Şimdi gönül rahatlığıyla database’e kaydetme işlemini gerçekleştirebiliriz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//...
[HttpPost]
public IHttpActionResult AddCategory(CategoryModel _model)
{
Categories cat = new Categories()
{
CategoryName = _model.KategoriAdi,
Description = _model.Aciklamasi
};
db.Categories.Add(cat);
db.SaveChanges();
return Ok();
}
|
- Tekrar aynı request’i gönderirek bu sefer veritabanına kaydedildiğini görüyoruz.
- Böylece temel veritabanı işlemimizi gerçekleştirdik.
Cross Origin (CORS) – Başka Domainden Erişme
- Geliştirdiğimiz API’ye client tarafından erişmek istediğimizde şöyle bir hata ile karşılaşmamız olasıdır:
- Bu bir güvenlik mekanizması aslında. API’mize yabancı bir adresten
erişilmesi durumunda browser http header’ında bunun için bir izin
arıyor. Bu noktada servisten tüm client’ların veri okumasına izin
verebiliriz. Böylece yalnız kendi domaininden değil internetteki başka
biri de bu bilgiye erişilebilir.
- Bunu da
Web.config dosyası içerisinden <system.webServer> altına şu satırları ekleyerek yapacağız:
|
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
|
- Artık servisten herhangi bir data get etmek isteyen herkese erişim izni veriyoruz.
- Buradaki
* isteyen herkesin bu dataya erişebilmesi anlamına geliyor.
- Bu noktada server tarafında gereken işlemleri tamamladık. Artık
geriye aşağıdaki gibi bir client aracılığıyla veriyi düzenlemek kalıyor.
- Client için bir
MVC projesi oluşturabilir veya basit bir web sayfası kullanarak ajax ile erişim sağlayabiliriz.
- Client tarafı bir Android uygulaması da olabilir. Burada önemli olan
web api
ile bir API oluşturup araya bir katman sokarak bir soyutlama sağlamış
olmaktır. Ardından ise bu katmanın güvenliğini sağlamak gerekir.
- Client kısmını ise bir sonraki yazıda ele alacağız.
- ASP.net’in sitesine girdiğimizde gerek Web API gerekse MVC konusunda gerekli dökümanlara ulaşabiliriz.
|