https://buraksenyurt.com/Burak Selim Şenyurt - REST2018-08-21T23:27:32+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/nasil-bir-web-api-tasarimiNasıl bir Web API Tasarımı?2018-08-05T21:30:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2018/07/restful_guid_1.gif" alt="" />Merhaba Arkadaşlar,</p>
<p>Web API'ler ya da RESTful API türünden servisler çok uzun zamandır hayatımızda. Benim de gerek blog yazılarımdaki örnekler olsun gerek iş yerinde kullandıklarımız olsun sürekli haşırneşir olduğum enstrümanlardan birisi. Ancak son zamanlarda okuduğum kaynaklardan sonra bir çok tasarım hatası yaptığımı ve uygulamadığım şeyler olduğunu fark ettim. Nedir bu işin doğru yolu diyerek ortak standartları araştırmaya başladım. Elde ettiğim bir takım sonuçlar oldu. Bu sonuçlardan basit bir çizelge de hazırladım. Aşağıda görebilirsiniz. Ama öncesinde bir kaç kısa bilgi verelim.</p>
<p>Bu tip servisler çoğunlukla kaynaklarla(resources) ilgili temel işlemleri gerçekleştirmek için kullanılmakta. Kaynakların listelenmesi, eklenmesi, silinmesi veya güncellenmesi söz konusu temel operasyonlar olarak düşünülebilir. Servisler, kaynaklarla ilgili operasyonları belli adresler(endpoint diyebiliriz) üzerinden sunar. Servislerin, sundukları kaynakların ve endpoint'lerin sayısı arttıkça baştan düşünülmesi gereken standartlar olduğunu fark ederiz. Özellikle bu servisler farklı takımlarca geliştiriliyorsa. Bu noktada kaynakların isimlendirilmesinden servis adresinin nasıl olacağına, versiyon bilgisinden serileştirme formatının bildirimine, operasyon adlarından döndürülecek HTTP cevaplarından istemciden hangi metodlarla gelineceğine kadar bir çok farklı kavram karşımıza çıkıyor. Bu konulardan bir kısmı ile ilgili olarak şunları söyleyebiliriz.</p>
<p>İsimlendirme standardı olarak aşağıdaki gibi kullanımlar öneriliyor.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">https://blog.fabrikamai.com/sample/api/v1/categories
https://api.fabrikamai.com/v1/categories</pre>
<p>İki kullanımdan birisi tercih edilebilir ama benim önerdiğim ikincisi. Dikkat edileceği üzere her iki tanımlamada versiyonlama bilgisi içermekte. Bazı kaynaklar versiyon bilgisinin Header içerisinde gönderilebileceğini de dile getiriyor ancak yukarıdaki yazımda olduğu gibi açık olması daha doğru. </p>
<p>HTTP Header kısmında daha çok istemci ve sunucu arasındaki mesajlaşmanın formatı belirtiliyor. Content-type ile request, Accept ile de response formatlarını belirtmemiz mümkün.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">Content-Type: application/json
Accept: application/json</pre>
<p>Diğer yandan sadece HTTP-Post ve Get desteği olan istemciler için mutlak suretle X-HTTP-Method-Override kullanılması bekleniyor. Bu konu ile ilgili <a href="https://buraksenyurt.com/post/Post-Gorunumlu-Put" target="_blank">şu yazıma</a> bakabilirsiniz.</p>
<p>Resource isimlendirmelerinde de çoğul ifadelerin kullanılması öneriliyor. Yani category yerine categories şeklinde tanımlama yapmak lazım. Diğer kullanım önerilerini de şu şekilde özetleyebiliriz<em>(<a href="https://buraksenyurt.com/file.axd?file=/2018/07/RESTfulAPI.xlsx">Excel dosyasını indirmek için tıklayın</a>)</em></p>
<p><em><img src="https://buraksenyurt.com/image.axd?picture=/2018/08/rest_table.png" alt="" /></em></p>
<p>Artık elimde/elinizde RESTful API tasarlamak için güzel bir kılavuz var. Bir başka yazıda görüşmek dileğiyle hepinize mutlu günler dilerim.</p>2018-08-05T21:30:00+00:00web apiasp.net web apirestfulrest based serviceshttppostputgetdeleteservicestandartsbsenyurtWeb API'ler dahası RESTful API türünden servisler çok uzun zamandır hayatımızda. Benim de gerek blog yazılarımdaki örnekler olsun gerek iş yerinde kullandıklarımız olsun sürekli haşırneşir olduğum enstrümanlar. Ancak son zamanlarda okuduğum kaynaklardan sonra bir çok isimlendirme hatası yaptığımı fark ettim. Nedir bu işin doğru yolu diyerek ortak standartları araştırmaya başladım. Elde ettiğim bir takım sonuçlar oldu. Bu sonuçlardan basit bir çizelge de hazırladım. Öncesinde bir kaç kısa bilgi verelim.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=6591e1a4-8097-4873-b847-72bc548664368https://buraksenyurt.com/trackback.axd?id=6591e1a4-8097-4873-b847-72bc54866436https://buraksenyurt.com/post/nasil-bir-web-api-tasarimi#commenthttps://buraksenyurt.com/syndication.axd?post=6591e1a4-8097-4873-b847-72bc54866436https://buraksenyurt.com/post/tek-fotoluk-ipucu-132-iis-restful-api-denemesiIIS RESTful API Hello World2016-05-19T17:00:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2016/05/iisrestful_3.gif" alt="" />Merhaba Arkadaşlar,</p>
<p>Bugün 20 Mayıs Cuma. Dün 19 Mayıs nedeniyle resmi tatil olan bankamız bugün de toplu olarak tatil. Ancak şirkette kalmak isteyenler durumlarını bildirip gelebiliyor.</p>
<p>Çalıştığım şirkettlerde işlerin hafiflediği dönemler genellikle makale yazdığım dönemler oluyor. Hazır geçtiğimiz gün de<strong> IIS Restful API</strong> hakkında araştırmalara başlamışken bugün biraz daha üzerine eğileyim, şu <strong>Hello World</strong> uygulamasını yaparak nedir ne değildir anlayayım istedim. Malzemelerimi hazırladım. En önemlisi elbetteki kafeindi. Her ne kadar çalışma masamdaki kadim dostum <strong><a href="http://www.lego.com/en-us/mixels/products/series-1/41501-vulk" target="_blank">VULK</a></strong> kahveme sulansa da...</p>
<p>Öğrendiğime göre <strong>Microsoft IIS<em>(Internet Information Services)</em></strong> takımı yönetimsel işlemler için <strong>Asp.Net Core</strong> teknolojisini kullanan <strong>RESTFul </strong>tipinden<strong> </strong>bir<strong> </strong>servis üzerinde çalışmalar yapmakta. <strong>Micro Service</strong> mimarisi benimsenerek geliştirilen alt yapı, kullanıcılarına <strong>IIS Administration</strong> ile ilgili gerekli fonksiyonellikleri modern bir API olarak sunuyor. <strong>API</strong>,<strong> Self-Hosted Window Service</strong> olarak yayınlanmakta. <strong>In-Proc</strong> çalışmalar için <strong>Hostable</strong> <strong>Web</strong> <strong>Core</strong> yapısına da sahip. Aşağıdaki şekil teknik mimarisi hakkında biraz daha fikir verecektir. <em>(Takımın çizdiği mimari resim kadar başarılı değil ama bakmadan çizmeye çalışırsanız konuyu güzelce pekiştirebilirsiniz)</em></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/05/IISRestful_2.gif" alt="" /></p>
<p>Bildiğiniz üzere <strong>IIS</strong>, <strong>Microsoft</strong> cephesinde kod geliştirenlerin yakından tanıdığı bir host uygulama olarak düşünülebilir. <strong>Web sitelerini<em>(asp.net, asp vb)</em></strong>, <strong>servisleri<em>(asmx, wcf vb)</em></strong>, <strong>HTTP Handler</strong> ve <strong>Module</strong>' leri bu uygulama üzerinden kolayca yayınlayabiliyoruz. <span style="line-height: 1.8;"><strong>IIS Manager</strong><em>(komut satırından inetmgr aracı ile)</em> gibi arayüzleri de kullanarak istediğimiz yönetsel işlemleri<em>(Application Pool' ların yönetimi, SSL'in açılıp kapatılması, site konfigurasyonlarının yapılması, Session ayarlamaları, yönlendirmeler, Handler yüklemeleri vb)</em> görsel olarak yapabilmekteyiz. </span></p>
<p><span style="line-height: 1.8;">Aslında <strong>.Net</strong> tarafında <strong>IIS</strong>'i kod bazlı yönetebiliyoruz. Ancak şu aşamada sunulan <strong>RESTFul API</strong> ile istemci tarafı teknolojisini de bağımsızlaştırılıyor. Bir başka deyişle herhangi bir türden istemci<em>(Client)</em> IIS ile ilgili yönetsel işlemleri <strong>RESTFul</strong> servise göndereceği basit <strong>HTTP</strong> çağrıları ile gerçekleştirebilecek<em>(Gelecek zaman kullanıyorum çünkü proje henüz geliştirilme aşamasında)</em> Yani <strong>Powershell</strong>' den yönetim yapılabileceği gibi <strong>Java</strong> ile yazılmış bir istemci de kullanılabilir. Hatta bu yönetsel operasyonlar mobil cihazlara kadar indirgenebilir. </span></p>
<blockquote>
<p><span style="line-height: 1.8;">İşten çıktınız ve eve gidiyorsunuz. Bir uyarı mesajı geldi. Test sunucusundaki sitelerden birisi sorun yaşıyor. IIS Reset değil ama sitenin Recycle edilmesi geçici bir çözüm olabilir. Mobil cihazınızdan o an sorun yaşayan bu siteyi Recycle ettiğinizi, bazı konfigürasyon ayarlarını değiştirebildiğinizi düşünsenize. Tabii güvenilir bir oturum çerçevesinde ki IIS takımı SSL sertifika ve API' ye özel Key:Value bilgileri ile bunu sağlıyor.</span></p>
</blockquote>
<p><span style="line-height: 1.8;"><strong>IIS</strong> takımının bu çalışmalarını test edebilmek için sunulan örnek bir site de var. <strong><a href="https://buraksenyurt.com/admin/app/editor/%20https:/jimmyca-srv2.cloudapp.net:55539" target="_blank">Azure üzerinde host edilen siteye</a></strong> genel kullanıma açık bir <strong>Authentication Token</strong> ile ulaşılabiliyor. </span></p>
<h2>Örnek Kod</h2>
<p><span style="line-height: 1.8;">Peki <strong>Microservice</strong> mimarisine göre tasarlanmış<strong> Asp.Net Core</strong> üzerinde oturan bu <strong>RESTFul</strong> <strong>API</strong>'yi<strong> .Net</strong> tabanlı bir istemci ile nasıl kullanabiliriz? Çok zor olmasa gerek değil mi? Altı üstü geçerli bir sertifika oluşturup <strong>REST</strong> tabanlı çağrı gerçekleştireceğiz. Dikkat edilmesi gereken noktalar, <strong>HTTP</strong> taleplerinin <strong>Header</strong> bilgisi içerisinde geçerli <strong>Key</strong> ve <strong>Value</strong> değerleri ile gönderilmesi ve sunucu bazlı sertifika doğrulatma işleminin yapılması. Gelin bunları göz önünde bulundurarak örnek <strong>Console</strong> uygulama kodlarımızı aşağıdaki gibi yazalım.</span></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
namespace UnitsNetHelloWorld
{
class Program
{
static void Main(string[] args)
{
IISManager manager = new IISManager();
Console.WriteLine("App Pools\n{0}",manager.GetAppPools());
Console.WriteLine("Default Web Site\n{0}", manager.GetDefaultWebSiteInformations());
Console.WriteLine("Web Sites\n{0}", manager.GetWebSites());
}
}
class IISManager
{
const string thumbprint = "3BEA286D400717ACA726181593B827955115EDFC";
const string headerKey = "X-Authorization";
const string headerValue = "Bearer OgMks6N7CtZTptX2DTnLe8JvkmATOuqw1ZJnZzK1RojeYs251Wlfvg";
const string rootPath = "https://jimmyca-srv2.cloudapp.net:55539/";
public IISManager()
{
ServicePointManager.ServerCertificateValidationCallback
= (sender, certificate, chain, sslPolicyErrors) =>
{
X509Certificate2 apiCert = certificate as X509Certificate2;
return apiCert == null ? false : apiCert.Thumbprint == thumbprint;
};
}
public string GetAppPools()
{
return Get(String.Concat(rootPath,"api/webserver/application-pools"));
}
public string GetWebSites()
{
return Get(string.Concat(rootPath,"api/webserver/websites"));
}
public string GetDefaultWebSiteInformations()
{
return Get(string.Concat(rootPath,"api/webserver/websites/QnizhC7cy49v1mIHNH5Gdw"));
}
public string Get(string request)
{
string result=string.Empty;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add(headerKey, headerValue);
var response = client.GetAsync(request).Result;
if (response.StatusCode == HttpStatusCode.OK)
result=response.Content.ReadAsStringAsync().Result;
}
return result;
}
}
}</pre>
<p><span style="line-height: 1.8;">Çalışma zamanı çıktısı aşağıdaki gibi olacaktır. </span></p>
<p><span style="line-height: 1.8;"><img src="https://buraksenyurt.com/image.axd?picture=/2016/05/IISRestful_1.gif" alt="" /></span></p>
<p><span style="line-height: 1.8;">Tamam kabul ediyorum okunurluğu epey zor. <strong>Matrix</strong> kodları içerisinde yüzüyor gibiyiz. Sonuçlar <strong>JSON</strong> formatında gelmiş durumda. Burada <strong>Newtonsoft</strong>' u devreye sokup daha okunabilir çıktılar elde edebiliriz. Hatta <strong>JSON</strong>'dan tipe dönüştürüp sonuçların <strong>domain</strong> içerisinde anlamlı nesneler olarak ele alınmasını da sağlayabiliriz. Bilin bakalım ben bu kutsal görevi kime bırakacağım...</span></p>
<h2><span style="line-height: 1.8;">Peki Kodda Neler Oluyor?</span></h2>
<p><span style="line-height: 1.8;">En büyük yardımcımız <strong>IISManager</strong> isimli sınıfımız. Nesne örneği oluşturulurken <strong>ServicePointManager</strong> tipinden yararlanarak sunucu bazlı bir sertifika doğrulama işlemi icra ediyoruz. Çekirdek metodumuz <strong>Get</strong> isimli fonksiyon. Bu metod bir <strong>HttpClient</strong> nesnesinden yararlanarak <strong>HTTP</strong> taleplerini asenkron olarak gönderiyor. Kullanımı için <strong>HTTP</strong> paketinin <strong>Header</strong> kısmında yer alacak Key ve Value değerlerinin doğru girilmesi şart. </span></p>
<p><span style="line-height: 1.8;"><strong>GetAsync</strong> metoduna gelen parametre, <strong>API</strong> ile ilgili geçerli bir <strong>HTTP</strong> talebini içeriyor. Örneğin sunucuda yer alan <strong>Application Pool</strong>' ları görmek için buraya <strong>api/webserver/application-pools</strong> bilgisini vermemiz gerekiyor. Bu bilginin başına da <strong>Root</strong> Path içeriği eklenince istenilen adres oluşuyor <em>(https://jimmyca-srv2.cloudapp.net:55539/api/webserver/application-pools gibi)<strong> </strong></em></span></p>
<p><span style="line-height: 1.8;">Kolaylık olması açısından bir kaç <strong>HTTP</strong> çağrısını metodlaştırdık. <strong>GetWebSites</strong> ile web sitelerini <strong>GetDefaultWebSiteInformations</strong> ile <strong>Default Web Site</strong>' a ait temel bilgileri elde edebiliyoruz. Bazı adreslerden dönen sonuçlar kendi içerisinde farklı adresler de içeriyor. Örneğin siteleri çektiğimizde bu siteler ile ilişkili bilgilere ulaşabileceğimiz başka <strong>EndPoint</strong> adresleri ile de karşılaşıyoruz. Dolayısıyla yönetimsel açıdan aklımıza gelebilecek bir çok senaryoyu uygulamak mümkün. Pek tabi daha farklı talepler de girilebilir. <a href="https://jimmyca-srv2.cloudapp.net:55539/#/api/webserver" target="_blank">Tam liste için şu adrese bakabilirsiniz</a>.</span></p>
<p><span style="line-height: 1.8;">Söz konusu <strong>API</strong> halen daha geliştirilme aşamasında. Bu <strong>API</strong>'nin kendi <strong>IIS</strong> sunucularımızda nasıl kullanılacağına dair henüz bir bilgi edinebilmiş değilim ancak şirketlerin bu <strong>API</strong> ile kendilerine hoş yönetim araçları yazabileceği kanısındayım. Özellikle yönetsel fonksiyonellikleri mobilize olarak sunabilmek büyük bir nimettir diye düşünüyorum. DevOps kültüründe de kendine güzel bir yer edinecektir kanımca. </span><span style="line-height: 1.8;">Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</span></p>
<p><em><span style="line-height: 1.8;">Kaynak : <a href="https://blogs.msdn.microsoft.com/webdev/2016/05/09/introducing-the-iis-administration-api/">https://blogs.msdn.microsoft.com/webdev/2016/05/09/introducing-the-iis-administration-api/</a> </span></em></p>2016-05-19T17:00:00+00:00iis.net coreasp.net corerestful apirestful servicesmicroservicec#bsenyurtÖğrendiğime göre Microsoft IIS(Internet Information Services) takımı yönetimsel işlemler için Asp.Net Core teknolojisini kullanan RESTFul tipinden bir servis üzerinde çalışmalar yapmakta. Micro Service mimarisi benimsenerek geliştirilen alt yapı, kullanıcılarına IIS Administration ile ilgili gerekli fonksiyonellikleri modern bir API olarak sunuyor. API, Self-Hosted Window Service olarak yayınlanmakta. In-Proc çalışmalar için Hostable Web Core yapısına da sahip. Aşağıdaki şekil teknik mimarisi hakkında biraz daha fikir verecektir. (Takımın çizdiği mimari resim kadar başarılı değil ama bakmadan çizmeye çalışırsanız konuyu güzelce pekiştirebilirsiniz)https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=5c398f41-5149-4bd8-8861-c411d14abf5f0https://buraksenyurt.com/trackback.axd?id=5c398f41-5149-4bd8-8861-c411d14abf5fhttps://buraksenyurt.com/post/tek-fotoluk-ipucu-132-iis-restful-api-denemesi#commenthttps://buraksenyurt.com/syndication.axd?post=5c398f41-5149-4bd8-8861-c411d14abf5fhttps://buraksenyurt.com/post/instagram-rest-servislerinin-net-tarafinda-kullanimiInstagram REST Servislerinin .Net Tarafında Basit Kullanımı2016-05-04T06:00:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2016/05/UsingInstagram_3.gif" alt="" />Merhaba Arkadaşlar,</p>
<p>Neredeyse hepimizin sosyal ağ üzerinde hesapları bulunuyor. <strong>Facebook, Twitter, Instagram, Youtube, Flickr</strong> ve benzerlerini bunlara örnek olarak verebiliriz. Bu ağlar pek tabii kendi hizmetlerini geliştiricilerin kullanımına da uzun zamandır açmış durumdalar. Geliştirici olarak bizleri bu kısım daha çok ilgilendiriyor.</p>
<p>Peki bu tip ağlar geliştiricilere kendi hizmetlerini nasıl sunuyorlar? Bunun en bilinen ve ortak yanı pek tabii ki servisler şeklinde yayınlanmaları. Burada kullanılacak olan servislerin istemci uygulamaların ne tipte olduğuna bakılmaksızın ortak bir standartta çalışması önemli. İşte bu noktada devreye <strong>REST<em>(Representational State Transfer)</em></strong> yaklaşımını benimseyen servisler geliyor. Neredeyse pek çok sosyal ağın <strong>REST</strong> tipinden hizmet veren <strong>Endpoint</strong>' leri mevcut. Bu sayede istemci teknolojilerinden tamamen bağımsız olarak dış dünyaya fonksiyonellikler sunulabilmekte. İşte bu yazımızda <strong>Instagram</strong>' ın dışarıya sunduğu bu <strong>REST</strong> servisleri nasıl kullanabileceğimizi basit bir Endpoint üzerinden incelemeye çalışacağız. Amacımız Instagram hesabı ile giriş yapan bir kullanıcının eklediği son fotoğrafları web sayfası üzerinde gösterbilmek.</p>
<blockquote>
<p>Aslında Instagram API'sinin .Net dünyasında daha kolay kullanımını sağlayan NuGet paketleri de mevcut. Kod tarafında nesne odaklı modeli kullanmak çok daha mantıklı. Ancak bizim amacımız REST taleplerini Instagram servislerine yaparken çalışma mimarisini de anlamaya çalışmak. Yazıyı bu şekilde değerlendirmenizi tavsiye ederim.</p>
</blockquote>
<p>Dilerseniz hiç vakit kaybetmeden işlemlerimize başlayalım.</p>
<h2>Instagram'a Uygulamamızın Kayıt Edilmesi(Registration)</h2>
<p>Öncelikle Instagram' a gidip uygulamamız için bir <strong>kayıt işlemi<em>(Register)</em></strong> gerçekleştirmeli ve kullanıcı girişi sonrası yönlendirilecek olan sayfa adresini bildirmeliyiz<strong><em>(Redirect URL)</em></strong>.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/05/UsingInstagram_1.gif" alt="" /></p>
<p>Bu kayıt işleminde önemli olan bir kaç nokta var. <strong>Client ID</strong>, <strong>Client Secret</strong> ve <strong>Redirect URI</strong> değerleri istemci uygulama tarafından kullanılacak değişkenler olacak. Geliştireceğimiz örnekte bu değerleri ele alarak <strong>Instagram</strong>' a erişim hakkı olan bir <strong>jeton<em>(Access Token)</em></strong> elde edeceğiz. Bir başka deyişle uygulamanın <strong>REST</strong> <strong>Endoint</strong>' lerini kullanabilmesi için gerekli izni alacağız. Özellikle <strong>Redirect URI</strong> değeri önemli. Nitekim uygulamamız üzerinden bir Login işlemi de gerçekleştirilmekte. Bu Login işlemi sonrasında geriye dönülecek olan <strong>URL</strong> bilgisi, <strong>Instagram</strong>' a kayıt edilen adres ile eş olmalı. Aksi durumda bir <strong>Authentication</strong> hatası alırız.</p>
<blockquote>
<p>Instagram API'sinin kullanımı ile ilişkili oldukça detaylı bir doküman da mevcut. Plaftorm bağımsız olarak yazılmış dokümanı inceleyerek kullanılabilecek <a title="REST Endpoint' leri hakkında detaylı bilgiye" href="https://www.instagram.com/developer/endpoints/" target="_blank">REST Endpoint' leri hakkında detaylı bilgiye</a> ulaşabilirsiniz.</p>
</blockquote>
<h2>Uygulama Kodlarının Geliştirilmesi</h2>
<p>Şimdi gelin boş bir web uygulaması açıp içerisine koyacağımız Default.aspx sayfasının kodlarını geliştirmeye başlayalım ve Instagram' a giriş yapan kişinin<em>(ki bu senaryoda ben oluyorum)</em> paylaştığı son fotoğrafları ekrana basalım.</p>
<p>Default.aspx.cs içeriğimiz şu şekildedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Net;
using System.Web.UI;
namespace InstagramRESTHello
{
public partial class Default : System.Web.UI.Page
{
static string code = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Request["code"]) && !Page.IsPostBack)
{
code = Request["code"].ToString();
GetUserIdAndAccessToken();
}
}
public void GetUserIdAndAccessToken()
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add("client_id", ConfigurationManager.AppSettings["ClientID"].ToString());
parameters.Add("client_secret", ConfigurationManager.AppSettings["ClientSecret"].ToString());
parameters.Add("grant_type", "authorization_code");
parameters.Add("redirect_uri", ConfigurationManager.AppSettings["RedirectUri"].ToString());
parameters.Add("code", code);
WebClient client = new WebClient();
var result = client.UploadValues("https://api.instagram.com/oauth/access_token", "POST", parameters);
var response = System.Text.Encoding.Default.GetString(result);
var returnContent = (JObject)JsonConvert.DeserializeObject(response);
string accessToken = (string)returnContent["access_token"];
string id = returnContent["user"]["id"].ToString();
var script = string.Format("<script>var userId = \"{0}\"; var accessToken = \"{1}\";</script>",
id,
accessToken
);
Page.ClientScript.RegisterStartupScript(this.GetType(), "GetToken",script);
}
protected void btnGetLastPhotos_Click(object sender, EventArgs e)
{
var clientId = ConfigurationManager.AppSettings["ClientID"];
var clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
var redirectPage = ConfigurationManager.AppSettings["RedirectUri"];
var loginUrl = string.Format("https://api.instagram.com/oauth/authorize/?client_id={0}&redirect_uri={1}&response_type=code"
, clientId, redirectPage);
Response.Redirect(loginUrl);
}
}
}</pre>
<blockquote>
<p>Instagram REST servisleri varsayılan olarak JSON formatından içerik döndürmektedir. Bu nedenle gelen cevapların ayrıştırılmasını kolaylaştırmak amacıyla Newtonsoft.JSON paketinden yararlanılmaktadır. Bu paketi yüklemeyi unutmayalım. NuGet Console' dan yüklemek için install-package Newtonsoft.Json yazmamız yeterlidir.</p>
</blockquote>
<p>Kodumuzda neler yaptığımızı kısaca anlatalım. Öncelikle uygulamamızın <strong>Instagram API</strong>'sinden yararlanabilmesini sağlamak için izin almamız gerekir. Bu izin için <a href="https://api.instagram.com/oauth/access_token">https://api.instagram.com/oauth/access_token</a> adresine <strong>HTTP</strong> <strong>POST</strong> tipinden bir paket gönderilir. <strong>Instagram</strong>' a kayıt ettiğimiz uygulama ile ilgili bilgiler gönderilecek pakete <strong>anahtar-değer<em>(key-value)</em></strong> koleksiyonu şeklinde eklenir. <strong>client_id</strong>, <strong>client_secret</strong>, <strong>grant_type</strong>, <strong>redirect_uri</strong> ve <strong>code</strong>. Eğer <strong>POST</strong> işlemi sonucu başarılı ise gelen cevap <strong>JSON</strong> formatında ters serileştirilerek <strong>access_token</strong> ve <strong>id</strong> bilgileri yakalanır. Bu bilgiler sayfaya <strong>register</strong> edilecek bir <strong>Javascript</strong> fonksiyonu için gereklidir. Nitekim çekilen <strong>id</strong> ve <strong>access_token</strong> bilgisini <strong>jQuery</strong> içerisindeki <strong>REST</strong> çağrısında kullanacağız.</p>
<p>Gelelim Default.aspx içeriğine.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="InstagramRESTHello.Default" %>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js" type="text/javascript"></script>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnGetLastPhotos" Text="Son Fotoğrafları Getir" runat="server" OnClick="btnGetLastPhotos_Click" />
</div>
<div>
<h2>Son Fotoğraflarım</h2>
<div id="PhotosDiv">
<ul id="PhotosUL">
</ul>
</div>
</div>
<div style="clear: both;">
</div>
<script type="text/javascript">
function GetLastPhotos() {
$("#PhotosUL").html("");
$.ajax({
type: "GET",
async: true,
contentType: "application/json; charset=utf-8",
url: 'https://api.instagram.com/v1/users/' + userId + '/media/recent?access_token=' + accessToken,
dataType: "jsonp",
cache: false,
beforeSend: function () {
$("#loading").show();
},
success: function (data) {
$("#loading").hide();
if (data == "") {
$("#PhotosDiv").hide();
} else {
$("#PhotosDiv").show();
for (var i = 0; i < data["data"].length; i++) {
$("#PhotosUL").append("<li style='float:left;list-style:none;'><a target='_blank' href='" + data.data[i].link + "'><img src='" + data.data[i].images.thumbnail.url + "'></img></a></li>");
}
}
}
});
}
$(document).ready(function () {
GetLastPhotos();
});
</script>
</form>
</body></pre>
<p>Sayfada yer alan <strong>Son Fotoğrafları Getir</strong> başlıklı buton'a basıldığında aslında önceden <strong>login</strong> olunmamışsa <strong>Instagram</strong> üzerinden bir giriş işlemi yaptırılır. Giriş işlemini takiben akış tekrardan Default.aspx sayfasına yönlenir<em>(Instagram'a dönülürken nereye gidileceği bilgisini uygulamamızı register ederken söylemiştik)</em> Eğer dönüş başarılı ise<strong> GetLastPhotos</strong> isimli javascript içeriği devreye girer. Bu fonksiyon içerisinde <strong>Instagram</strong> <strong>REST</strong> <strong>Endpoint</strong>'lerine <strong>Ajax servis çağrısı</strong> gerçekleştirilir. <strong>HTTP GET</strong> tipinden yapılan bu çağrıda içerik tipi<em><strong>(content-type)</strong></em> <strong>JSON</strong> olarak bildirilir. Ayrıca asenkron tipte bir çağrı yapılacağı da belirtilmiştir<strong><em>(async:true)</em></strong>. <strong>url</strong> niteliğine verilen değerde ise talep edilen fonksiyonelliğe ait adres bilgisi yer alır. Tabii burada kullanılan <strong>userId</strong> ve <strong>accessToken</strong> değerlerinin, <strong>GetUserIdAndAccessToken</strong> metodu içerisinden verildiklerine dikkat edelim<em>(O script'i bu yüzden sayfaya register ettik)</em> Eğer işlemler başarılı bir şekilde gerçekleşirse <strong>success</strong> bloğundaki kod bloğu devreye girecek ve ilgili div söz konusu kullanıcının son fotoğrafları ile dolacaktır. Örneğin aşağıdaki gibi :)</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/05/UsingInstagram_2.gif" alt="" /></p>
<p>Görüldüğü gibi son fotoğraflarımız geldi. Hatta içlerinden istenilen bir tanesine tıklayabilir ve <strong>Instagram</strong> üzerindeki geçerli adresine gidebiliriz. <strong>url</strong> içeriğini değiştirerek farklı talepleri de test edebiliriz. Örneğin tag bazlı veya popüler olan fotoğrafları, sizi takip eden kullanıcıları, sizin takip ettiklerinizi, belli bir fotoğrafı ya da video'yu beğenenleri vb...Kısacası <strong>Instagram</strong> için yazılmış herhangibir uygulamanın yapabileceği pek çok şeyi <strong>REST</strong> <strong>Endpoint</strong>'leri kullanarak gerçekleştirmeniz mümkün. </p>
<p>Bu örnekte bir <strong>Instagram REST Endpoint</strong>'ini kullanarak son 25 fotoğrafımızı web sayfası üzerine nasıl basabileceğimizi gördük. Dikkat edilmesi gereken nokta çalışma prensibi. Öncelikle Instagram'dan uygulamamız için izin aldık. Bu izin karşılığında bize verdiği jetonu ve kendisine uygulamamız üzerinden giriş yaptığımızı kullanıcı bilgisine ele alarak sorgu işlemi gerçekleştirdik. Elde ettiğimiz JSON içeriklerini sayfa üzerinde uygun bir şekilde kullandık ve vakamızı tamamladık. Böylece geldik bir makalemizin daha sonuna. Tekrar görüşünceye dek hepinize mutlu günler dilerim.</p>2016-05-04T06:00:00+00:00instagramrest servicesWebClientjsonc#jqueryjavascriptendpoint behaviorapinugetbsenyurtNeredeyse hepimizin sosyal ağ üzerinde hesapları bulunuyor. Facebook, Twitter, Instagram, Youtube, Flickr ve benzerlerini bunlara örnek olarak verebiliriz. Bu ağlar pek tabii kendi hizmetlerini geliştiricilerin kullanımına da uzun zamandır açmış durumdalar. Geliştirici olarak bizleri bu kısım daha çok ilgilendiriyor. Peki bu tip ağlar geliştiricilere kendi hizmetlerini nasıl sunuyorlar? Bunun en bilinen ve ortak yanı pek tabii ki servisler şeklinde yayınlanmaları. Burada kullanılacak olan servislerin istemci uygulamaların ne tipte olduğuna bakılmaksızın ortak bir standartta çalışması önemli. İşte bu noktada devreye REST(Representational State Transfer) yaklaşımını benimseyen servisler geliyor.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=a4397012-3589-4016-af34-fe5a1c2b2a3c8https://buraksenyurt.com/trackback.axd?id=a4397012-3589-4016-af34-fe5a1c2b2a3chttps://buraksenyurt.com/post/instagram-rest-servislerinin-net-tarafinda-kullanimi#commenthttps://buraksenyurt.com/syndication.axd?post=a4397012-3589-4016-af34-fe5a1c2b2a3chttps://buraksenyurt.com/post/klasik-asp-sayfasindan-rest-servis-cagirmakKlasik ASP Sayfasından REST Servis Çağırmak2016-02-24T12:00:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2016/02/asprest_0.gif" alt="" />Merhaba Arkadaşlar,</p>
<p>Özellikle kurumsal çözümler üreten/kullanan firmalarda görev alanların sıklıkla dahil olduğu vakalardan birisi de, eski ve yeni teknolojilerin iç içe kullanıldığı senaryolardır. Bazen geliştirilen ürünler yıllara varan yaşam döngüleri boyunca çalışmaya devam eder. Yenileme maliyetlerinin yüksek olması nedeniyle de tekrardan yazılmak yerine var olan yeni teknolojiler ile entegre edilmeye çalışılırlar. </p>
<p>İşte geçtiğimiz günlerde yine bizim turuncu bankamızda buna benzer bir ihtiyaç doğdu. Klasik <strong>ASP</strong> ile yazılmış ve neredeyse 10 yaşından büyük olan bir ürünün yeni nesil bir teknoloji ile entegre olması gerekti. Söz konusu <strong>ASP</strong> uygulaması bunca yıl çalıştığı için üzerine eklenen kodlar sebebiyle tam bir <a href="https://sourcemaking.com/antipatterns/lava-flow">Lawa-Flow AntiPattern</a> oluşmasına da sebebiyet vermişti. <em>(İçine giren kayboluyor herhangibir yerine müdahale etmek gerçekten yürek istiyordu)</em> Ancak kullanıcı alışkanlıkları, yenileme maliyetleri ve kaynak sıkıntısı nedeniyle tekrardan yazılamıyordu. Ürünün güncel sıkıntısı ise içerdiği <strong>C tabanlı API</strong>'nin yeni nesil <strong>64bit</strong> sunucularda çalışmamasıydı. İlgili kütüphane yıllarca önce dış kaynak bir firma tarafından yazılmıştı. İlgili firmadan çözüm için destek alınabilirdi. Şayet firma hala var olsaydı. Var olan C kütüphanesi banka dışı kurum ile <strong>SNA</strong> isimli eski bir protokol üzerinden haberleşme yapan fonksiyonellikler içeriyordu. Ne var ki dış kurum yakın zamanda bu protokolü terk edip TCP/IP tabanlı bir alt yapıya geçeceğini duyurmuştu. Dolayısıyla C kütüphanesinin değiştirilmesi öncelikli bir gereksinim haline gelmişti. <span style="line-height: 1.8;">Çözüm olarak C kütüphanesinin gerçekleştirdiği bu haberleşmeyi üstlenen </span><strong style="line-height: 1.8;">REST</strong><span style="line-height: 1.8;"> tipinden bir servisin devreye alınmasına karar verildi. Problem basitti; <strong>.Net</strong> ile geliştirilecek olan <strong>REST</strong> servisin, <strong>HTTP POST/GET </strong>gibi metodlar ile çalışacak operasyonları klasik <strong>ASP</strong> sayfasından nasıl tüketilebilirdi? <em>(Senaryomuzu şekilsel olarak aşağıdaki gibi özetleyebiliriz. Aslında canlı halini görseniz sarı kağıt üzerinde kurşun kalemli olan bu çizim gayet renkli ve canlı duruyor)</em></span></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/asprest_1.gif" alt="" /></p>
<h2>REST Servisin Geliştirilmesi</h2>
<p>Şimdi bu problemi nasıl çözebileceğimize bir bakalım. İlk olarak basit bir <strong>WCF REST </strong>servis geliştireceğiz. Burada <strong>Web API</strong>, <strong>Service Stack</strong> veya diğer özel bir çözüm kullanabiliriz<em>(<a href="https://buraksenyurt.com/post/ruby-kod-parcaciklari-20-rest-servis-gelistirmek" target="_blank">İlgili servisi Ruby ile yazabiliriz örneğin</a>)</em> Sonuç itibariyle <strong>REST</strong> tabanlı çalışan bir servise ihtiyacımız var. Ben basit olması açısından boş bir web uygulaması açıp içerisine aşağıdaki servis içeriğini eklemeyi tercih ettim.</p>
<p>ICommonService isimli servis sözleşmemiz</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
using System.ServiceModel.Web;
namespace ServiceSilo
{
[ServiceContract
(Namespace="http://www.buraksenyurt.com/services/silo/common"
,Name="CommonOperation")
]
public interface ICommonService
{
[OperationContract]
[WebInvoke(
Method="POST"
,ResponseFormat=WebMessageFormat.Xml
,RequestFormat=WebMessageFormat.Xml
,BodyStyle=WebMessageBodyStyle.Wrapped
,UriTemplate="doWork"
)]
string DoWork(string input);
}
}</pre>
<p>Servis sözleşmesinde önemli olan noktaların başında <strong>WebInvoke</strong> <strong>niteliğinin<em>(attribute)</em></strong> kullanımı gelir. Dikkat edileceği üzere <strong>POST</strong> tipinden bir <strong>HTTP</strong> metod bildirimi söz konusudur<em>(Tabii siz kendi denemelerinizde GET, PUT ve DELETE operasyonlarını da işin içerisine katabilirsiniz)</em> Operasyonumuzun adı <strong>doWork</strong> olarak ifade edilmiştir. <strong>Request</strong> ve <strong>Response</strong> mesaj formatları ise <strong>XML</strong> şeklindedir. Klasik <strong>ASP</strong> tarafında <strong>XML</strong> ile daha rahat çalışabileceğimizi düşündüğümüzden bu yönde bir tercih yaptığımızı belirtebilirim. </p>
<blockquote>
<p>Web uygulamasında REST bazlı servis özelliklerini kullanabilmek için projeye System.ServiceModel.Web assembly' ının referans edilmesi gerekmektedir.</p>
</blockquote>
<p>CommonService içeriği</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
namespace ServiceSilo
{
public class CommonService
: ICommonService
{
public string DoWork(string input)
{
string result = string.Format("{0}-Incoming Messaage : {1}",DateTime.Now.ToLongTimeString(),input);
return result;
}
}
}</pre>
<p><strong>DoWork</strong> metodu özel bir şey yapmıyor. Sadece gelen içeriği alıp bir string değişkende kullanarak geri döndürüyor. Pek tabii gerçek hayat senaryosunda <strong>Data Transfer Object</strong> gibi <strong>request</strong> ve <strong>response</strong> formatları da kullanılabilir. Yani bir <strong>Entity</strong> içeriğinin<em>(örneğin bir Kategori tipinin parametre olarak geçilip buna bağlı ürün listesinin döndürülmesi)</em> parametre olarak geçişmesi ve buna göre bir karmaşık tipin gönderilmesi söz konusu olabilir. Şu an için önemli olan bu mesaj yapılarının klasik <strong>ASP</strong> tarafında nasıl kullanıldığıdır.</p>
<p>web.config </p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpRuntime targetFramework="4.5.1" />
</system.web>
<system.serviceModel>
<services>
<service name="ServiceSilo.CommonService" behaviorConfiguration="RestBehavior">
<endpoint
address=""
binding="webHttpBinding"
contract="ServiceSilo.ICommonService"
behaviorConfiguration="web"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RestBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp helpEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration></pre>
<p>Servis uygulamasına ait konfigurasyon içeriğinde dikkat edilmesi gerekenler <strong>webHttp</strong> <strong>endPoint</strong> davranışının uygulanması ve <strong>webHttpBinding</strong> <strong>Binding</strong> tipinin kullanılmış olmasıdır. Böylece servis uygulamamız <strong>HTTP</strong> <strong>Post</strong>, <strong>Put</strong>, <strong>Get</strong> ve <strong>Delete</strong> gibi metodlara cevap verebilecek çalışma ortamına kavuşmuş olacaktır. Örneği <strong>IIS</strong> üzerine <strong>publish</strong> ettikten sonra aşağıdaki ekran görüntüsündekine benzer yardım içeriklerine erişebilmemiz gerekmektedir.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/asprest_2.gif" alt="" /></p>
<h2>Klasik ASP Sayfasının Geliştirilmesi</h2>
<p>Senaryo gereği <strong>doWork</strong> isimli metoda bir <strong>POST</strong> çağrısı gerçekleştirmek istiyoruz. Bu nedenle <strong>ASP</strong> tarafında <strong>XML</strong> paketi şeklinde oluşturacağımız içeriği göndermenin yolunu bulmamız gerekiyor. Bunun için <strong>MSXML2.ServerXMLHTTP</strong> nesnesinden yararlanacağız. Örnek olarak aşağıdaki <strong>default.asp</strong> içeriğini göz önüne alabiliriz.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><html>
<head>
<title>REST Service Call Sample</title>
</head>
<body bgcolor="black" text="green">
<form method="post" action="default.asp">
Input : <input type="text" name="txtInput"/>
<p/>
<input type="submit" value="HTTP Post"/>
</form>
<%
Dim input
input=Request.Form("txtInput")
set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
xmlhttp.open "POST", "http://localhost/ServiceSilo/CommonService.svc/doWork", false
xmlhttp.setRequestHeader "Content-Type", "text/xml"
xmlhttp.send "<string xmlns='http://schemas.microsoft.com/2003/10/Serialization/'>"&input&"</string>"
serviceResponse = xmlhttp.responseText
httpResponse = xmlhttp.status
httpStatusText = xmlhttp.statustext
set xmlhttp = nothing
Response.Write("HTTP Status : " & httpResponse & "<p/>")
Response.Write("Response : " & httpStatusText& "<p/>")
Response.Write("Response text : " & serviceResponse& "<p/>")
%>
</body></pre>
<p>Aslında <strong>ASP </strong>formu oldukça basit. <strong>Submit</strong> işlemi gerçekleştirildiğinde yine kendi üzerine dönen bir sayfa söz konusu. <strong>txtInput</strong> içeriği <strong>Request.Form</strong> ile alındıktan sonraki kısım bizim için daha önemli. <strong>MSXML2.ServerXMLHTTP</strong> nesnesi örneklendikten sonra <strong>open</strong> metoduna üç parametre veriyoruz. İlki <strong>HTTP</strong> metodunun tipi, ikincisi talebin gönderileceği adres<em>(ki sondaki doWork uzantısına dikkat edelim)</em> sonuncusu ise işlemin asenkron olarak gerçekleştirilip gerçekleştirilmeyeceğidir. <strong>open</strong> çağrısı sonrası <strong>HTTP</strong> <strong>Header</strong> için <strong>içerik tipi<em>(Content-Type)</em></strong> belirlenir. Paketler <strong>XML </strong>formatında gönderilecektir. Nitekim servis tarafının kabul ettiği format budur<em>(WebInvoke niteliğini bir kontrol edin)</em> İzleyen adımda <strong>send</strong> metodu ile paket gönderimi gerçekleştirilir. Burada içeriğin <strong>XML </strong>formatında olduğunda lüften dikkat edelim. <strong>XML</strong> içeriğinin nasıl olması gerektiği noktasında, <strong>REST</strong> servisin <strong>help</strong> sayfasından yardım alabiliriz(<strong>http://localhost/ServiceSilo/CommonService.svc/help</strong>)</p>
<blockquote>
<p>Yazılan ASP sayfasının IIS 7.5 üzerinde host edildiğini belirteyim. Bu işlem sırasında Application Pool'un Classic modda çalıştırıldığında, IUSR kullanıcısı için Permission ayarlarının yapıldığını belirtmek isterim. IIS üzerinde klasik ASP kullanımı makale sınırlarımız dışında olduğundan derinlemesine detaylandırmıyorum.</p>
</blockquote>
<p>Yapılan çağrıya ait sonuçlar <strong>xmlhttp</strong> değişkeni üzerinden yakalanbilirler. <strong>responseText</strong> ile gelen cevabı, <strong>status</strong> ile <strong>HTTP</strong> durum kodunu, <strong>statustext</strong> ile de durum koduna ait açıklamayı yakalayabiliriz. Bu işlemin ardından yapılan tek şey elde edilen sonuçları ekrana basmaktır. Örnek başarılı bir şekilde çalıştığında aşağıdakine benzer bir sonuç görülebilir.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/asprest_3.gif" alt="" /></p>
<p>Özetleyecek olursak eski nesil bir <strong>ASP</strong> sayfasından, yeni nesil <strong>REST</strong> tipinden bir servisi çağırmayı başarabildiğimizi ifade edebiliriz. Tabii ki bu benim nasıl yapılır sorusu için uğraştığım ilk kod parçası. Asıl ihtiyacımızda bu servis entegrasyonunun var olan miras uygulamasının hangi <strong>ASP</strong> sayfalarında yapılacağının bulunması, gelen içeriklerin kodda kullanılabilir kıvama getirilmesi gibi gereksinimler söz konusu. Bize kolay gelsin. Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2016-02-24T12:00:00+00:00httprestrest servicesasp.netclassic aspwcfhttp postMSXML2ServerXMLHTTPbsenyurtÖzellikle kurumsal çözümler üreten/kullanan firmalarda görev alanların sıklıkla dahil olduğu vakalardan birisi de, eski ve yeni teknolojilerin iç içe kullanıldığı senaryolardır. Bazen geliştirilen ürünler yıllara varan yaşam döngüleri boyunca çalışmaya devam eder. Yenileme maliyetlerinin yüksek olması nedeniyle de tekrardan yazılmak yerine var olan yeni teknolojiler ile entegre edilmeye çalışılırlar.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=424e5052-b6ee-4eea-80cb-2a1713b83fee3https://buraksenyurt.com/trackback.axd?id=424e5052-b6ee-4eea-80cb-2a1713b83feehttps://buraksenyurt.com/post/klasik-asp-sayfasindan-rest-servis-cagirmak#commenthttps://buraksenyurt.com/syndication.axd?post=424e5052-b6ee-4eea-80cb-2a1713b83feehttps://buraksenyurt.com/post/servicestack-ile-rest-servis-gelistirmekServiceStack ile REST Servis Geliştirmek2016-02-13T07:00:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2016/02/cat.gif" alt="" />Merhaba Arkadaşlar,</p>
<p>Geçenlerde üzerinde çalışmakta olduğum proje için kullandığım geliştirme ortamımı bir güzelce patlatıverdim. <strong>Oracle</strong>'ın yeni sürümüne ait <strong>Data Provider</strong>' ın,<strong> .Net Framework 4.5.2</strong> sürümüne yükseltmiş bir uygulamada neden çalışmadığını araştırıyordum. Sorun sunucu kaynaklı idi. Vakayı geliştirme ortamında da oluşturmaya çalıştım. Nitekim orada her şey yolunda görünüyordu. Lafı fazla uzatmayayım sonunda <strong>Production </strong>ortamını da kurcalamaya karar verdim...Eee...Şey...Orayı da patlattım :) Neyseki prod sunucusu sadece kurulumu yapılmış ve henüz yayına alınmamış bir makine idi. Zaten uygulamanın orada başarılı şekilde çalışması halinde kullanıma açılacak bir sunucuydu. Durumu ben, sistem ekibindeki bir kaç kişi ve ekip arkadaşım biliyordu. Ah şu andan itibaren de siz. Dolayısıyla hafif stresli günler geçirdiğimi ifade edebilirim. Epeyce sinirlendim ve sakinleşmek için her zaman yaptığım şeyi yaptım. Makale yazdım. </p>
<p>Bu kez gözüme faydalı olduğunu düşündüğüm bir <strong>Nuget</strong> paketini kestirdim. <a href="http://www.servicedesignpatterns.com/requestandresponsemanagement/datatransferobject">DTO servis tasarım desenini</a> baz alan <strong>ServiceStack</strong>.</p>
<blockquote>
<p>Arada sırada NuGet paketlerini indirip kullanmaya çalışmakta fayda var. Nitekim bu paketleri kullanırken uyguladıkları kalıpları veya mimari yaklaşımları da inceleme fırsatı buluyoruz.</p>
</blockquote>
<p><strong>ServiceStack</strong>, <strong>WCF</strong> ve <strong>Asp.Net Web API</strong>' ye alternatif olarak kullanılabilecek bir <strong>Web Service Framework</strong>'ü. Standart <strong>SOAP</strong> tabanlı servisler dışında <strong>REST</strong> tabanlı servislerin geliştirilmesine de izin veren bir çatı. Host uygulamalar <strong>IIS</strong>, <strong>Windows Service</strong> ya da <strong>Self-Hosted</strong> teknikleri ile yayınlanabiliyor. Hatta <strong>mono</strong> üzerinden de servisleri host etmek mümkün ki bu da farklı platformlar üzerinden servis yayınlanmasına imkan sağlıyor. Çok fazla konfigurasyon gerektirmeden kolayca geliştirme yapılması mümkün.</p>
<p>Aslında <strong>Data Transfer Object<em>(DTOs)</em></strong> olarak adlandırılan servis tasarım kalıbını benimsemekte. Bu modele göre servis uç noktalarına gelecek olan <strong>talepler<em>(Requests)</em></strong> ve <strong>cevaplar<em>(Response)</em></strong> birer nesne olarak tanımlanıyor. Bir servisin tanımlanması için zaten en az bir talep için <strong>DTO</strong> sınıfının yazılması gerekmekte. Servisler birer <strong>Endpoint</strong> olarak sunuluyor. <strong>Route</strong> tanımlamaları ise<em>(yani hangi HTTP talebinin ele alınacağının çalışma ortamına bildirimesi ve uygun yönlendirmenin yapılması)</em> <strong>Asp.Net Web API</strong>'den farklı olarak <strong>service controller</strong> yerine <strong>DTO</strong> seviyesinde uygulanıyor. Tüm bunlar biraz kafanızı karıştırmış olabilir. Gelin basit bir örnek üzerinden konuyu anlamaya çalışalım.</p>
<h2>Senaryo</h2>
<p><strong>Console</strong> uygulaması üzerinden <strong>host</strong> edilen bir <strong>REST</strong> servis geliştireceğiz. Bu servisin şimdilik <strong>HTTP</strong> <strong>Get</strong> ve <strong>Post</strong> için birer operasyonu olacak. Ancak kendi çalışmanız sırasında <strong>Put</strong> ve <strong>Delete</strong> gibi operasyonları da senaryoya dahil edebilirsiniz. Servisimiz <strong>Product</strong> tipinden bir nesne koleksiyonunu kullanacak. <strong>Get</strong> operasyonları ile adı belirli bir metin ile başlayan ürünlerin listesini veya tümünü döndüreceğiz. <strong>Post</strong> operasyonu ile de yeni bir ürünü listeye ekleyeceğiz. <strong>Host</strong> uygulamasını, <strong>localhost</strong> üzerinde bizim belirleyeceğimiz uygun bir <strong>Port</strong>'tan ayağa kaldıracağız. Kısacası <strong>Self-Hosted</strong> bir program söz konusu olacak. İstemci tarafında ise basit bir tarayıcıdan veya <strong>SoapUI </strong>aracından yararlanabiliriz. Temel hedefimiz <strong>Http</strong> <strong>Get</strong> ve <strong>Post</strong> taleplerini yaparak sonuçları görebilmek. </p>
<h2>Servis Tarafı</h2>
<p>İlk olarak bir <strong>Console</strong> uygulaması açarak işe başlayalım. Sonrasında <strong>ServiceStack</strong> paketini uygulamamıza dahil etmemiz gerekiyor. </p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sStack_3.gif" alt="" /></p>
<p>Paketi dahil ettikten sonra aşağıdaki sınıf diagramını baz alarak gerekli geliştirmeleri yapmaya başlayabiliriz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sstack_4.gif" alt="" /></p>
<p>ve kodlar</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
namespace HowToServiceStack
{
class Program
{
static void Main(string[] args)
{
var hostAddress = "http://*:4568/";
var appHost = new AppHost().Init().Start(hostAddress);
Console.WriteLine("Host is running at {0}",hostAddress);
Console.ReadLine();
}
}
#region POCOs
public class Product
{
public int PartNumber { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
}
#endregion
#region DTOs
[Route("/Products","GET")]
[Route("/Products/{NameLike}","GET")]
public class ProductSelectRequest
:IReturn<ProductSelectResponse>
{
public string NameLike { get; set; }
}
public class ProductSelectResponse
{
public List<Product> Products { get; set; }
}
[Route("/products","POST")]
public class CreateProduct
:IReturn<ProductSelectResponse>
{
public int PartNumber { get; set; }
public string Name { get; set; }
public decimal ListPrice { get; set; }
}
#endregion
#region Service Implementation
public class ProductService
: Service
{
public static List<Product> products = new List<Product>
{
new Product{ PartNumber=1001, Name="AC-210",ListPrice=1000},
new Product{ PartNumber=1002, Name="AC-215",ListPrice=960},
new Product{ PartNumber=1003, Name="KC-210",ListPrice=850.50M},
new Product{ PartNumber=1004, Name="BC-210",ListPrice=750},
new Product{ PartNumber=1005, Name="BD-123",ListPrice=450},
new Product{ PartNumber=1006, Name="BD-400",ListPrice=900},
new Product{ PartNumber=1007, Name="ZD-405",ListPrice=250},
new Product{ PartNumber=1008, Name="CD-505",ListPrice=385}
};
public object Get(ProductSelectRequest request)
{
if(request.NameLike!=default(string))
{
return new ProductSelectResponse
{
Products = (from p in products
where p.Name.StartsWith(request.NameLike)
select p).ToList()
};
}
else
{
return new ProductSelectResponse
{
Products = products
};
}
}
public object Post(CreateProduct request)
{
Product newProduct = new Product
{
PartNumber = request.PartNumber,
Name = request.Name,
ListPrice = request.ListPrice
};
products.Add(newProduct);
return newProduct;
}
}
#endregion
public class AppHost
: AppSelfHostBase
{
public AppHost()
:base("HttpListener Self-Host",typeof(ProductService).Assembly)
{
}
public override void Configure(Funq.Container container)
{
}
}
}</pre>
<h2>Kodda Neler Yaptık?</h2>
<p>İlk olarak <strong>AppHost</strong> sınıfına bir bakalım. <strong>AppSelfHostBase</strong>' den türetilmiş olan bu sınıf temel olarak <strong>Host</strong> uygulama görevini üstleniyor. Ayrıca <strong>ProductService</strong> isimli servisin hizmete alınması işlemlerini gerçekleştiriyor. Uygulama <strong>http://localhost:4568</strong> adresi üzerinden yayın yapacak. Buna göre <strong>Main</strong> metodu içerisinde <strong>Init().Start(hostAddress)</strong> formasyonunu kullanıyoruz<em>(Burada Fluent stilde bir tasarım olduğu gözden kaçmamalıdır. Fleunt kod tasarımı için <a href="https://buraksenyurt.com/post/Fluent-Interface-Prensibi-ile-Daha-Okunabilir-Kod-Gelistirmek.aspx">bu yazıya</a> bakabilirsiniz) </em></p>
<p>Yukarıda da bahsettiğimiz üzere <strong>ServiceStack</strong> <strong>DTO </strong>servis tasarım desenini kullanmaktadır. <strong>/products/ ve /products/{NameLike}</strong> şeklinde yapılacak <strong>HTTP</strong> <strong>Get</strong> talepleri için <strong>ProductSelectRequest</strong> isimli bir <strong>DTO</strong> tipi tanımlanmıştır. <strong>ProductSelectRequest</strong> sınıfı <strong>IReturn<ProductSelectResponse></strong> <strong>arayüzünü<em>(Interface)</em></strong> uygulamaktadır. Buna göre çalışma zamanı <strong>/Products</strong> veya <strong>/Products/{NameLike}</strong> talepleri karşısında nasıl bir tip döndüreceğini de öğrenmektedir. </p>
<p><strong>ProductSelectRequest </strong>sadece <strong>NameLike</strong> isimli bir özellik içermektedir. Hatta bu özellik <strong>Route</strong> niteliğinde de birebir kullanılmaktadır. İstemci tarafından gelecek talebin çeşitliliğine göre <strong>DTO</strong> sınıflarına n sayıda özellik de katılabilir. <strong>Get</strong> taleplerine olan cevabımız temel olarak bir ürün listesidir. Bu nedenle <strong>ProductSalesResponse</strong> sınıfı içerisinde <strong>List<Product></strong> tipinden bir özellik bulunmaktadır. </p>
<p><span style="line-height: 1.8;">Bir diğer <strong>DTO</strong> tipi ise <strong>CreateProduct</strong> sınıfıdır. Bu sınıf yeni bir ürünü listeye eklemek için gerekli özellikleri içermektedir. <strong>Route</strong> niteliğinde bir önceki <strong>DTO</strong> nesnesinden farklı olarak <strong>POST</strong> bildirimi yapılmıştır. Her iki <strong>DTO</strong> üzerinde de <strong>Route nitelikleri<em>(Attributes)</em></strong> kullanılmıştır. İlk parametreler <strong>resource</strong> bilgisini, ikinci parametreler ise <strong>HTTP</strong> metodunu ifade etmektedir. </span></p>
<p><span style="line-height: 1.8;">Uygulamanın can alıcı noktası ise tahmin edileceği üzere <strong>ProductService</strong> isimli hizmettir. Servis, <strong>Get</strong> ve <strong>Post</strong> isimli iki fonksiyon içerir. Her iki metodda dikkat edileceği üzere <strong>DTO</strong> nesnelerini parametre olarak almaktadır. Get metodu ile ürün koleksiyonu üzerinde <strong>Name</strong> alanının değerine göre arama yaptırılır. Eğer <strong>NameLike</strong> değeri verilmemişse tüm ürün listesi döndürülür. <strong>Post</strong> metodu ise basitçe <strong>products</strong> değişkenine yeni bir <strong>Product</strong> nesne örneği ilave etmektedir.</span></p>
<p><strong>ProductService</strong> sınıfnın bulunduğu <strong>Assembly</strong> dikkat edileceği üzere <strong>AppHost</strong> sınıfının yapıcı metodunda kullanılmakta ve <strong>base</strong> sınıfın yapıcı metoduna yönlendirilmektedir. Çalışma zamanının gelen <strong>Assembly</strong> bildirimine göre hangi tipleri servis olarak devreye alacağı <strong>Service</strong> sınıfından yapılan <strong>türetme<em>(Inheritance)</em></strong> sayesinde bilinmektedir. Bir başka deyişle<strong> Application Host</strong> çalışma zamanının Service türevli tipleri birer hizmet olarak yayına alacağını ifade edebiliriz.</p>
<p>Aslında yaptıklarımızı aşağıdaki şekil ile kısaca özetleyebiliriz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sStack_6.gif" alt="" /></p>
<h2>Testler</h2>
<p>Öncelikli olarak servisi ayağa kaldırmamız gerekiyor. <strong>Console</strong> uygulamasını başlattığımızda aşağıdakine benzer bir ekran görüntüsü ile karşılaşmalıyız.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sStack_0.gif" alt="" /></p>
<p>Sonrasında istemci testlerine başlayabiliriz. Ben, <strong>Get</strong> ve <strong>Post</strong> talepleri için <strong>SoapUI</strong> ve <strong>Google Chrome</strong> tarayıcısından yararlandım. <strong>SoapUI </strong>üzerinden elde ettiğim sonuçlar ise şöyle.</p>
<p><strong>http://localhost:4568/products/ HTTP Get</strong> için</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sStack_1.gif" alt="" /></p>
<p><strong>ServiceStack</strong> istemci tarafına özel bir <strong>HTML</strong> içeriği basar. İstenirse çıktılar <strong>json</strong>,<strong>xml</strong>,<strong>csv</strong> ve hatta <strong>jsv</strong> formatında alınabilir. Tek yapılması gereken <strong>URL</strong> sonuna <strong>?format=json</strong> benzeri bir ifade eklemektir. Örneğin <span style="text-decoration: underline;">ürün adı B harfi ile başlayanların listesini JSON formatında elde etmek istersek</span> <strong>http://localhost:4568/Products/B?format=json</strong> şeklinde bir talep gönderilmesi yeterlidir.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sstack_5.gif" alt="" /></p>
<p>ve <strong>http://localhost:4568/products/ HTTP Post</strong> içinde aşağıdaki şekilde talepte bulunabiliriz. Eğer <strong>Post</strong> paketi başarılı bir şekilde gönderilirse servisin yeni üretilen <strong>Product</strong> nesnesine ait değerleri geri gönderdiğini de görebilmeliyiz. Aynen aşağıdaki ekran görüntüsünde olduğu gibi.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2016/02/sStack_2.gif" alt="" /></p>
<p>Bu işlem sonrasında ürün listesi yeniden talep edilirse <strong>1000</strong> numaralı parçanın da koleksiyona eklendiği görülecektir. Tabii ki bir gerçek hayat senaryosunda veriyi tutmak adına <strong>RDBMS</strong> veya <strong>NoSQL</strong> tabanlı bir kaynaktan yararlanmakta yarar vardır. Siz antrenmanlarınızı buna göre yapabilirsiniz.</p>
<p>Bu makalemizde <strong>ServiceStack</strong> paketini kullanarak <strong>Self-Hosted REST</strong> servislerini nasıl geliştirebileceğimizi basit bir örnek üzerinden incelemeye çalıştık. Anlamamız gereken önemli noktalardan birisi de <strong>DTO</strong> servis tasarım kalıbının nasıl kullanıldığıdır. Ayrıca <strong>Service</strong> türevli tiplerin çalışma zamanında servis şeklinde nasıl sunulabildiğinin, <strong>Route</strong> niteliklerinin görevlerini nasıl gerçekleştirdiğinin ve gelen talepler ile ilgili <strong>DTO</strong> nesnelerinin nasıl ele alındığının düşünülmesinde yarar vardır. Siz bu tip bir çatıyı tasarlamaya çalışsanız nasıl bir yol izler ve kodlama yapardınız? Bunu bir düşünün.</p>
<p>Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2016-02-13T07:00:00+00:00restserviceservice oriented architecturec#servicestackoopsoapuidtodata transfer objectservice design patternsbsenyurtServiceStack, WCF ve Asp.Net Web API' ye alternatif olarak kullanılabilecek bir Web Service Framework'ü. Standart SOAP tabanlı servisler dışında REST tabanlı servislerin geliştirilmesine de izin veren bir çatı. Host uygulamalar IIS, Windows Service ya da Self-Hosted teknikleri ile yayınlanabiliyor. Hatta mono üzerinden de servisleri host etmek mümkün ki bu da farklı platformlar üzerinden servis yayınlanmasına imkan sağlıyor. Çok fazla konfigurasyon gerektirmeden kolayca geliştirme yapılması mümkün.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=a6cf0ca6-369e-479a-ae97-f9adadd4c03e0https://buraksenyurt.com/trackback.axd?id=a6cf0ca6-369e-479a-ae97-f9adadd4c03ehttps://buraksenyurt.com/post/servicestack-ile-rest-servis-gelistirmek#commenthttps://buraksenyurt.com/syndication.axd?post=a6cf0ca6-369e-479a-ae97-f9adadd4c03e