https://www.buraksenyurt.com/Burak Selim Şenyurt - WCF 4.52016-08-08T07:25:29+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://www.buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://www.buraksenyurt.com/post/WCF-4-5-Built-In-UDP-DestegiWCF 4.5–Built-In UDP Desteği2015-01-17T23:00:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/70050.jpg"><img style="float: right; margin: 4px 0px; display: inline;" title="70050" src="/pics/70050_thumb.jpg" alt="70050" width="250" height="156" align="right" /></a>Merhaba Arkadaşlar,</p>
<blockquote>
<p>Hızzzzz!!! Ben Hızzımmm! Hızlıdan hızlı…</p>
</blockquote>
<p>Bu repliği bu aralar haftada en az 7 kere seyretmek zorunda kaldığım Cars filminden hatırlıyorum<em>(Pixar’ ın efsane çizgi filmlerinden birisi olmakla birlikte serinin 2nci filmi de süperdir. 3ncü çekilir mi bilemem ama çekilse harika olur)</em></p>
<p>Şimşek McQueen filmin baş ve ana karakteri olarak çok hızlı bir arabadır ve tek derdi çok daha hızlı gitmektir. Hatta serinin ikinci bölümüne kapıştığı Formula 1 arabası dahil pek çok çeşitteki yarış otomobilini sürekli geride bırakır. Bunların arasında ralli araçlarından tutun, LeMans’ da yarışlanlara kadar pek çok çeşit vardır.</p>
<p>Aslında network ortamında da ona benzer bir kahraman bulunmaktadır. Onun gibi biraz güvenlikten ödün verir ama çok da hızlıdır. İşte bu yazımızda McQueen’ in network üzerindeki en büyük rakibi olan <strong>UDP</strong> protokolünü ve onun <strong>WCF 4.5</strong> tarafındaki kullanımını incelemeye çalışıyor olacağız.</p>
<h1>User Datagram Protocol</h1>
<p><strong>TCP/IP</strong> protokolünün katmanlarını incelediğimizde sırasıyla Ağ(Network), Internet, İletişim ve Uygulama katmanlarından oluştuğunu görürüz. İletişim katmanında <strong>TCP</strong> ve <strong>UDP<em>(User Datagram Protocol)</em></strong> olmak üzere iki farklı protokol seçeneği bulunmaktadır. <strong>UDP</strong> protokolü, minimum kabiliyet ile hızlı bir iletişimin kullanılabilmesine olanak tanımaktadır.</p>
<p><strong>UDP, Transaction</strong> yönlendirmeli bir protokoldür ve <strong>TCP</strong> gibi mesajın teslim edildiğine dair bir garanti <span style="text-decoration: underline;">beklememektedir</span>. Bu kontrolsüzlük, onun hızlı olmasının nedenlerinden de bir tanesidir. Diğer yandan, bu iletişim şekli nedeni ile verinin doğru iletilip iletilmediğini de kontrol <span style="text-decoration: underline;">etmemektedir</span>. Pek tabi hız için söz konusu olan bu ödün vermeler güvenli olmayan bir iletişimin de doğal sonucudur.</p>
<p>Dolayısıyla <strong>UDP</strong> protokolünün kullanım alanları <strong>TCP </strong>protokolününkine göre biraz daha farklıdır. Özellikle <strong>Wide Arena Network(WAN)</strong> tipindeki ağlarda, sesli ve görüntülü bilgi aktarımının çok sayıdaki istemciye, simultane olarak yüksek hızlarda aktarılabilmesi gibi vakalarda tercih edilmektedir. Nitekim bu hallerde sadece verinin karşı tarafta bekleyen istemcilere olabildiğince hızlı biçimde akması önemlidir.</p>
<blockquote>
<p>Ancak yine de dikkat edilmesi gereken bir durum vardır. UDP ve TCP, TCP/IP’ nin iletişim katında yer alan iki protokoldür. Bu sebepten ikisini aynı anda kullanabilmek de mümkündür. Böyle bir senaryoda, TCP’ nin yüksek veri transferi nedeniyle UDP’ nin performansı düşebilir.</p>
</blockquote>
<h1>WCF 4.5 Desteği</h1>
<p>Gelelim <strong>.Net</strong> <strong>Framework</strong> tarafına. <strong>Windows Communication Foundation 4.5</strong> sürümü ile birlikte, <strong>UDP</strong> protokolü için <strong>Built-In</strong> bir <strong>bağlayıcı tip(Binding Type)</strong> desteği sunmaya başlamıştır. Dolayısıyla <strong>UDP</strong> tabanlı servislerin yazılması çok daha kolay hale gelmiştir. Biz bu yazımızda, hem <strong>UdpBinding </strong>tipinin nasıl kullanıldığını görmeye çalışacak, hem de <strong>UDP</strong> ile <strong>TCP</strong>, <strong>Basic</strong> <strong>HTTP</strong> ve <strong>WS-HTTP</strong> gibi sık kullanılan mesajlaşma protokollerini hız bazında karşılaştıracağız. <strong>UDP’</strong> nin daha verimli ve performanslı olacağını düşünebiliriz. Özellikle tek yönlü iletişimde. Ama bunu ispat etmemiz ve sonuçları irdelememiz gerekiyor. Nitekim sürprizler olabilir.</p>
<blockquote>
<p>UDP nin WCF tarafındaki kullanımında dikkat edilmesi gereken noktalar şunlardır:</p>
<ul>
<ul>
<li>İletişim(Transport) veya mesaj(Message) seviyesinde güvenlik yoktur.</li>
<li>Adres şeması soap.udp:// şeklindedir.</li>
<li>Desteklenen encoding formatı Text’ dir.</li>
<li>Session, Transaction, Duplex iletişim ve Streaming desteği yoktur.</li>
</ul>
</ul>
<br />
<ul>
<ul>Bağlayıcı tiplerin güncel durumu ile ilişkili olarak</ul>
</ul>
<a href="http://msdn.microsoft.com/en-us/library/ms730879(v=vs.110).aspx" target="_blank">MSDN’ deki bu adresten</a>
<ul>daha detaylı bilgi alabilirsiniz.</ul>
</blockquote>
<h1>Örnek Senaryo</h1>
<p>Konuyu daha iyi anlayabilmek için basit bir çözüm üzerinden ilerlemeye çalışabiliriz. <strong>Solution</strong> içeriğimizde 3 farklı proje bulunacaktır. Bunlardan birisi <strong>WCF Servis</strong> kütüphanesi, diğeri bu servis kütüphanesini kullanan <strong>Host</strong> uygulaması ve 3ncüsü de istemci program. Servis ile istemci tarafındaki haberleşme de <strong>UDP, TCP</strong> ve <strong>HTTP</strong> bazlı iletişimi tercih ediyor olacağız. Amacımız <strong>UDP</strong> kullanımı ve performans testi olduğundan <strong>tek yönlü(OneWay)</strong> çalışan ve sadece basit bir <strong>string</strong> içeriği sunucuya gönderebilmemizi sağlayan bir <strong>servis sözleşmesi<em>(Service Contract)</em></strong> tasarlıyor olacağız. Kabaca gerçekleştirmeyi planladığımız senaryo aşağıdaki şekilde görüldüğü gibidir.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_2.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_2" src="/pics/udpwcf_2_thumb.png" alt="udpwcf_2" width="567" height="513" /></a></p>
<h1>Servis Kütüphanesinin Geliştirilmesi</h1>
<p>Dilerseniz ilk olarak <strong>WCF servis kütüphanesini(WCF Service Library)</strong> tasarlayalım.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_5.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_5" src="/pics/udpwcf_5_thumb.png" alt="udpwcf_5" width="232" height="253" /></a></p>
<p><strong>IEchoService</strong> sözleşmesi aşağıdaki kod içeriğine sahiptir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
namespace HighwayServiceLibrary
{
[ServiceContract]
public interface IEchoService
{
[OperationContract(IsOneWay=true)]
void SendEcho(string content);
}
}</pre>
<p>Burada dikkat edilmesi gereken nokta hız testi için <strong>SendEcho</strong> isimli servis operasyonunun <strong>OneWay</strong> çalışacak şekilde nitelendirilmiş olmasıdır. Buna göre istemciler <strong>SendEcho’</strong> dan bir dönüş beklemeyecek ve sadece sürekli veri gönderimi işlemini gerçekleştireceklerdir.</p>
<blockquote>
<p>Hatırlayacağınız gibi OneWay, asenkron servis çağırma tekniklerinden birisidir.</p>
</blockquote>
<p>Servis sözleşmesine ait implementasyon ise aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace HighwayServiceLibrary
{
public class EchoService
:IEchoService
{
public void SendEcho(string content)
{
//Do Something
}
}
}</pre>
<p>Eeee bu kod hakkında söylenecek pek fazla bir şey yok aslında <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="/pics/wlEmoticon-smile_57.png" alt="Smile" /></p>
<h1>Servis Tarafının Geliştirilmesi</h1>
<p>Servis tarafını yazarak ilerleyelim. <strong>Console</strong> uygulaması olarak tasarlayacağımız <strong>host</strong> programın en önemli özelliği birden fazla <strong>EndPoint</strong> üzerinden hizmet verecek olmasıdır. Bu nedenle <strong>App.config </strong>dosyası içeriği oldukça önemlidir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="StandartBehavior">
<serviceMetadata/>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="HighwayServiceLibrary.EchoService" behaviorConfiguration="StandartBehavior">
<endpoint address="http://localhost:54160/basic/EchoService" binding="basicHttpBinding" contract="HighwayServiceLibrary.IEchoService"/>
<endpoint address="http://localhost:54160/ws/EchoService" binding="wsHttpBinding" contract="HighwayServiceLibrary.IEchoService"/>
<endpoint address="http://localhost:54160/EchoService/mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<endpoint address="soap.udp://localhost:54162/EchoService" binding="udpBinding" contract="HighwayServiceLibrary.IEchoService"/>
<endpoint address="net.tcp://localhost:54161/EchoService" binding="netTcpBinding" contract="HighwayServiceLibrary.IEchoService"/>
</service>
</services>
</system.serviceModel>
</configuration></pre>
<p>Dikkat edileceği üzere <strong>Basic HTTP<em>(SOAP 1.1 oluyor)</em>, WS HTTP, TCP</strong> ve <strong>UDP</strong> destekli <strong>EndPoint</strong> tanımlamaları yapılmıştır. Bunlara ek olarak istemci tarafının servise ait <strong>metadata</strong> bilgisini çekebilmesi için de bir <strong>Metadata</strong> <strong>Exchange</strong> erişim noktası ilave edilmiştir.</p>
<blockquote>
<p>Hatırlayalım!</p>
<p>Metadata paylaşımı için kullanılan sözleşme tipi .Net Framework içerisinde Built-In olarak gelen IMetadataExchange arayüzünde(Interface) tanımlanmıştır.</p>
</blockquote>
<p><strong>Host</strong> uygulamaya ait kod içeriği ise şu şekildedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using HighwayServiceLibrary;
using System;
using System.ServiceModel;
namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
using(ServiceHost host=new ServiceHost(typeof(EchoService)))
{
host.Open();
Console.WriteLine(@"Uygulama sunucusunu durumu: ""{0}"" ",host.State);
Console.WriteLine("Uygulama sunucusunu kapatmak için bir tuşa basınız.");
Console.ReadLine();
host.Close();
}
}
}
}</pre>
<p>Standart olarak basit bir <strong>Self-Host</strong> uygulama kodu görülmektedir. Çok doğal olarak istemcilerin servisi kullanabilmesi için uygulamanın çalışır halde olması ve <strong>host </strong>bağlantısının açık olması <em><strong>(Host.State=Open)</strong></em> önemlidir.</p>
<blockquote>
<p>İstemci tarafında Add Service Reference seçeneği ile Proxy tipini üretirken, servis uygulamasının da açık olması gerektiğini unutmayalım.</p>
</blockquote>
<h1>İstemci Tarafının Geliştirilmesi</h1>
<p>Gelelim istemci tarafına. Servis referansını ekledikten sonra istemci tarafında aşağıdaki <strong>config</strong> içeriğinin üretildiği gözlemlenecektir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IEchoService" />
</basicHttpBinding>
<netTcpBinding>
<binding name="NetTcpBinding_IEchoService" />
</netTcpBinding>
<wsHttpBinding>
<binding name="WSHttpBinding_IEchoService" />
</wsHttpBinding>
<udpBinding>
<binding name="UdpBinding_IEchoService" />
</udpBinding>
</bindings>
<client>
<endpoint address="http://localhost:54160/basic/EchoService"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IEchoService"
contract="EchoSpace.IEchoService" name="BasicHttpBinding_IEchoService" />
<endpoint address="http://localhost:54160/ws/EchoService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IEchoService" contract="EchoSpace.IEchoService"
name="WSHttpBinding_IEchoService" />
<endpoint address="soap.udp://localhost:54162/UdpServiceHost"
binding="udpBinding" bindingConfiguration="UdpBinding_IEchoService"
contract="EchoSpace.IEchoService" name="UdpBinding_IEchoService" />
<endpoint address="net.tcp://localhost:54161/EchoService" binding="netTcpBinding"
bindingConfiguration="NetTcpBinding_IEchoService" contract="EchoSpace.IEchoService"
name="NetTcpBinding_IEchoService">
</endpoint>
</client>
</system.serviceModel>
</configuration></pre>
<p>Görüldüğü gibi <strong>4</strong> <strong>Endpoint</strong> erişim notkasına ait tanımlamalar <strong>config</strong> dosyası içerisine eklenmiştir. İstemci tarafındaki test kodlarımız ise aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using Highway.ClientApp.EchoSpace;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Highway.ClientApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Başlamak için bir tuşa basınız");
Console.ReadLine();
string testData = CreateRandomString();
Dictionary<EchoServiceClient,string> proxies = new Dictionary<EchoServiceClient,string>
{
{new EchoServiceClient("UdpBinding_IEchoService"),"UDP"},
{new EchoServiceClient("BasicHttpBinding_IEchoService"),"BASIC HTTP"},
{new EchoServiceClient("WSHttpBinding_IEchoService"),"WS HTTP"},
{new EchoServiceClient("NetTcpBinding_IEchoService"),"NET TCP"},
};
foreach (var proxy in proxies)
{
for (int i = 1; i < 5; i++)
{
Executer(proxy.Key, proxy.Value, i * 10000, testData);
}
proxy.Key.Close();
}
}
static void Executer(EchoServiceClient proxy,string title,int tryCount,string testData)
{
Stopwatch watcher = new Stopwatch();
watcher.Start();
for (int i = 0; i < tryCount; i++)
{
proxy.SendEcho(testData);
}
watcher.Stop();
Console.WriteLine("{0} Total Milliseconds {1}",title, watcher.ElapsedMilliseconds.ToString());
}
static string CreateRandomString()
{
char[] charachters = new char[4096];
for (int i = 0; i < charachters.Length; i++)
{
charachters[i] = 'S';
}
return new string(charachters);
}
}
}</pre>
<h1>Ne Yapıyoruz?</h1>
<p>Aslında yaptığımız işlem gayet basit. <strong>4096</strong> <strong>byte </strong>boyutu olan ve içerisinde<strong> S</strong> yazan metin katarlarımızı paketler halinde defalarca servis tarafına göndermekteyiz. Örnekte bu tekrar sayısı <strong>i*10000</strong> kadardır. Bu da bize test için gerekli veri aktarım yükünü getirecektir.</p>
<blockquote>
<p>Gönderimde bulunulacak olan UDP paketlerindeki Datagram içeriğinin belirli bir boyut sınırı vardır. En azından WCF tarafında bunun bir limiti bulunmaktadır. Eğer çok büyük boyutlu bir paket gönderilmeye çalışılırsa aşağıdakine benzer bir çalışma zamanı hatasının istemci tarafına çıkması muhtemeldir. Dikkat edileceği üzere 65507 byte’ ın aşılmaması gerektiği ifade edilmektedir.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_6.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_6" src="/pics/udpwcf_6_thumb.png" alt="udpwcf_6" width="508" height="401" /></a></p>
</blockquote>
<h1>Testler</h1>
<p>Artık uygulamamızı test edebiliriz. Ben kullanmakta olduğum sistemde yaptığım testler sonucu aşağıdaki ekran görüntüsündekine benzer çalışma zamanı süreleri ile karşılaştım.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_3.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_3" src="/pics/udpwcf_3_thumb.png" alt="udpwcf_3" width="338" height="290" /></a></p>
<p>Dikkat edileceği üzere <strong>UDP</strong> ile yapılan haberleşme diğerlerine göre çok daha hızlı. <strong>WS</strong> tabanlı yapılan iletişim ise yerlerde sürünüyor diyebiliriz bu sonuçlara göre. Nitekim WS iletişiminde paket sayısının belirgin ölçüde arttığını da belirtelim. Sonuçları <strong>Excel</strong> <strong>Chart</strong> ile yorumlarsak farkları daha net anlayabiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_4.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_4" src="/pics/udpwcf_4_thumb.png" alt="udpwcf_4" width="490" height="617" /></a></p>
<p><strong>UDP’</strong> ye özellikle <strong>OneWay</strong> erişimde en çok yaklaşan <strong>TCP</strong> protokolü üzerinden yapılan iletişimdir. Diğer yandan en uzun süreler <strong>WS HTTP</strong> tabanlı iletişimde gerçekleşmiştir. Bu son derece doğaldır nitekim söz konusu iletişim protokolünde <strong>WS</strong> standartları gereği <strong>Security’</strong> yi sağlamak için yapılan bir dizi zaman kaybettirici işlem söz konusudur.</p>
<h1>Peki Ya Request/Response Modunda</h1>
<p>Yapılan testler dikkat edileceği üzere <strong>OneWay</strong> çalışan bir servis operasyonu için geçerlidir. Peki <strong>Request/Response</strong> modeline göre çalışan operasyonlar için de durum aynı mıdır? Gelin son olarak bu vakayı da test etmeye çalışalım. Bunun için ilk olarak servis tarafına aşağıdaki test operasyonunu ekleyelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
namespace HighwayServiceLibrary
{
[ServiceContract]
public interface IEchoService
{
[OperationContract(IsOneWay=true)]
void SendEcho(string content);
[OperationContract]
string GetEcho(int length);
}
}</pre>
<p>Bu basit operasyonun implementasyonu çok da önemli değil aslında. Geriye tek bir karakter döndürse de olur. Asıl önemli nokta tüm protokoller için eşit olan bu operasyonun <strong>Request/Response</strong> modeline göre çalışıyor olmasıdır.</p>
<blockquote>
<p>Şu anda servis tarafındaki sözleşme(Service Contract) değişmiş durumdadır. Dolayısıyla istemci tarafındaki Proxy tipinin Update edilmesi gerekir<em>(Update Service Reference)</em></p>
</blockquote>
<p>İstemci tarafında ise aşağıdaki küçük kod değişikliğini yapmamız yeterlidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">static void Executer(EchoServiceClient proxy,string title,int tryCount,string testData)
{
.
.
.
for (int i = 0; i < tryCount; i++)
{
//proxy.SendEcho(testData);
proxy.GetEcho(1);
}
.
.
.
}</pre>
<p>Çalışma zamanında aşağıdaki ekran görüntüsündekine benzer sonuçlar alınmıştır.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_7.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_7" src="/pics/udpwcf_7_thumb.png" alt="udpwcf_7" width="313" height="310" /></a></p>
<p>Her zamanki gibi sonuçları <strong>Excel Chart</strong> üzerinden değerlendirirsek çok daha iyi analiz edebiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/udpwcf_8.png"><img style="margin: 4px 0px; display: inline;" title="udpwcf_8" src="/pics/udpwcf_8_thumb.png" alt="udpwcf_8" width="488" height="612" /></a></p>
<p>Liderlik dikkat edileceği üzere <strong>TCP</strong> bazlı iletişime geçti. İşte başta belirttiğimiz sürpriz durumlardan birisi. Aradaki farklar çok da az olsa <strong>UDP</strong> iletişiminden daha hızlı sonuçlar elde edildiğini görmekteyiz. Bu sonuçlara göre özellikle <strong>tek yönlü(OneWay)</strong> olarak tasarlanabilen, ses ile video gibi veri aktarımlarının söz konusu olduğu, güvenli olması gerekmeyen ve hatta içeriğin <strong>Streaming</strong> şeklinde değil de paketler halinde gönderilip n sayıda istemciye ulaştırılacağı düşünülen senaryolarda <strong>UDP</strong> tabanlı iletişimi tercih edebiliriz. Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2012%2f9%2fHighwayLast.zip">HighwayLast.zip (101,38 kb)</a></p>2015-01-17T23:00:00+00:00wcf,soa,windows communication foundation,header,soap envelope,message contract,xsd,xmlbsenyurtTCP/IP protokolünün katmanlarını incelediğimizde sırasıyla Ağ(Network), Internet, İletişim ve Uygulama katmanlarından oluştuğunu görürüz. İletişim katmanında TCP ve UDP(User Datagram Protocol) olmak üzere iki farklı protokol seçeneği bulunmaktadır. UDP protokolü, minimum kabiliyet ile hızlı bir iletişimin kullanılabilmesine olanak tanımaktadır. UDP, Transaction yönlendirmeli bir protokoldür ve TCP gibi mesajın teslim edildiğine dair bir garanti beklememektedir. Bu kontrolsüzlük, onun hızlı olmasının nedenlerinden de bir tanesidir. Diğer yandan, bu iletişim şekli nedeni ile verinin doğru iletilip iletilmediğini de kontrol etmemektedir. Pek tabi hız için söz konusu olan bu ödün vermeler güvenli olmayan bir iletişimin de doğal sonucudur.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=91c876f9-2b7a-4e19-9efe-37bb3aa3047f6https://www.buraksenyurt.com/trackback.axd?id=91c876f9-2b7a-4e19-9efe-37bb3aa3047fhttps://www.buraksenyurt.com/post/WCF-4-5-Built-In-UDP-Destegi#commenthttps://www.buraksenyurt.com/syndication.axd?post=91c876f9-2b7a-4e19-9efe-37bb3aa3047fhttps://www.buraksenyurt.com/post/WCF-ChannelFactory-Tipi-icin-Caching-KullanimiWCF 4.5–ChannelFactory Tipi için Caching Kullanımı2014-12-22T19:00:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/PerfectCircle.jpg"><img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border-width: 0px;" title="PerfectCircle" src="/pics/PerfectCircle_thumb.jpg" alt="PerfectCircle" width="240" height="240" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>Vaktiyle üniversitedeki diferansiyel denklemler dersi hocamızın anlattığı bir efsane vardı<em>(Sene 94 bu arada)</em>. Ne kadar gerçektir bilinmez ama beni oldukça etkilemişti. Hikayeye göre üniversite hocaları arasında belirli aralıklarla düzenlenen bir yarışma varmış. Bu yarışmada hocaların tahtaya kalkıp seçtikleri teoremlere ait geometrik şekilleri çizmeleri istenirmiş. En güzel çizim ise mükafatlandırılırmış.</p>
<p>Bir gün hocalar ardı ardına kalkıp tahtada hünerlerini göstermeye başlamışlar. Hemen hepsi rengarenk tebeşirler kullanıyormuş. Sarmallar, hiperboller, spiraller, üç boyutlu grafikler vb…</p>
<p>Derken sıra son yarışmacıya gelmiş. Hoca ayağa kalkmış yavaş adımlarla boş olan tahtalardan birine doğru yürümeye başlamış. Kısa bir süre durmuş ve diğer çizimlere imrenerek bakmış. Sonra önündeki boş tahtaya bir çember çizmiş ve ortasına da bir nokta yerleştirmiş.</p>
<p>Jüri diğer tahtaları dolaşıp puanladıktan sonra bu çemberin başında toplanmış. Çemberi ve ortadaki noktayı ölçüp biçmişler. Nokta, çemberin tam merkezindeymiş ve çember mükemmelmiş <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="/pics/wlEmoticon-smile_101.png" alt="Smile" /> Bu hikayenin yazımızın konusu ile doğrudan bir alakası yok tabi. Şöyle şehir efsanesi tadında bir giriş yapayım istedim. Gelelim asıl sıkıcı olan mevzumuza.</p>
<p>Bir <strong>WCF</strong><em>(Windows Communication Foundation)</em> servisi ile onun tüketicisi olan istemci arasındaki iletişimde önem arz eden konulardan birisi de kanaldır<em>(Channel)</em>. Bu kanalın oluşturulması görevini <strong>ChannelFactory</strong> tipi üstlenmektedir. İstemci açısından bakıldığında bir kanalın oluşturulması aslında servisin bir <strong>Proxy</strong> tipinin üretilmesi ve uzak metod çağrıları için gerekli iletişim ortamının sağlanması anlamına gelmektedir. Bir kanal esas itibariyle <strong>EndPoint</strong> odaklı üretilir. Dolayısıyla <strong>WCF</strong>' in <strong>ABC</strong>'si olarak nitelendirilen <strong>Address Binding Contract</strong> üçlemesi üzerine inşa olunur<em>(ki bu da <strong>WCF Service EndPoint</strong> tanımıdır)</em> </p>
<p>Tabi kanal üretimi sırasında devreye giren bir süreç de söz konusudur. Buna göre <strong>Sözleşme Tanımlama<em>(Contract Description)</em></strong> ağacının üretilmesi, gerekli <strong>CLR<em>(Common Language Runtime)</em> </strong>tiplerinin <strong>reflecting</strong> ile açılması, kanal yığınının<em><strong>(Channel Stack)</strong></em> inşa edilmesi ve üretilen kaynaklardan sonlanması gerekenlerin sonlandırılması<em>(Dispose işlemleri olarak düşünebiliriz)</em>. İşte bu süreç özellikle çalışma zamanına bir maliyet getirmektedir. Bu maliyeti aza indirgemek içinse genellikle özelleştirilmiş ChannelFactory tiplerinin yazılması yolu tercih edilir. Oysaki <strong>WCF 4.5 </strong>bu hazırlıkların kayıt altına alınıp yeniden ihtiyaç duyulduklarında hazır olarak sunulması için <strong>caching </strong>desteğini <strong>ClientBase<T> </strong>tipi yardımıyla kullanıma açmıştır. İşte bu yazımızdaki amacımız <strong>ChannelFactory</strong> tipi için ön bellekleme işleminin nasıl yapılabileceğini incelemektir.</p>
<h1>Ön Hazırlıklar</h1>
<p>Elbette konuyu incelemek için basit bir <strong>WCF</strong> servisine ihtiyacımız olacak. Konumuz <strong>ChannelFactory</strong> ve bazı ön hazırlıkların ön belleklenmesi olduğundan servis tarafı oldukça sade ve basit şekilde inşa edilmiştir. Aşağıda servis sözleşmesi<em>(Service Contract)</em> ve uygulayıcı tipini içeren bir <strong>WCF Service Application </strong>kod içeriği bulunmaktadır.</p>
<p><a href="https://www.buraksenyurt.com/pics/cfcache_1.png"><img style="margin: 4px 0px; display: inline;" title="cfcache_1" src="/pics/cfcache_1_thumb.png" alt="cfcache_1" width="215" height="276" /></a></p>
<p>Servis sözleşmesi;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
namespace Calculus
{
[ServiceContract]
public interface IMathService
{
[OperationContract]
double Sum(int x,int y);
}
}
Uygulayıcı tip;
using System;
namespace Calculus
{
public class MathService
: IMathService
{
public double Sum(int x, int y)
{
return x + y;
}
}
}</pre>
<p><strong>web.config</strong> dosyası içeriğini ise standart ayarları ile bırakabiliriz. İstemci tarafını basit bir <strong>Console</strong> uygulaması şeklinde tasarlayabilir ve ilgili servisi <strong>Add Service Reference</strong> ile ekleyebiliriz. İstemci tarafındaki <strong>app.config</strong> dosyası otomatik olarak aşağıdakine benzer biçimde oluşturulacaktır.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IMathService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:54837/MathService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IMathService" contract="clcls.IMathService"
name="BasicHttpBinding_IMathService" />
</client>
</system.serviceModel>
</configuration></pre>
<p> </p>
<h1>Standart Proxy Kullanımı</h1>
<p>Bu ön hazırlıkların ardından standart bir <strong>proxy</strong> kullanımı ile ilgili servisi kullanarak konumuza devam edelim. <strong>WCF</strong> servislerini çağırırken genellikle <strong>proxy</strong> tipinin doğrudan üretilmesi yolunu tercih ederiz. Söz gelimi aşağıdaki kod parçasında basit bir <strong>WCF</strong> servis çağrısı görülmektedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using Student.clcls;
using System;
namespace Student
{
class Program
{
static void Main(string[] args)
{
MathServiceClient proxy = new MathServiceClient("BasicHttpBinding_IMathService");
double result=proxy.Sum(3, 4);
Console.WriteLine(result.ToString());
proxy.Close();
}
}
}</pre>
<p>Hepimizin aşina olduğu bir kullanım şekli.</p>
<ol>
<li><strong>Client</strong> son eki ile biten sınıfa ait bir nesne örneği oluştur.</li>
<li>Parametre olarak konfigurasyon dosyası içerisindeki <strong>endPoint</strong> adını ver.</li>
<li>Örneklenen nesne üzerinden gerekli servis metodunu çağır.</li>
<li>Tüm işlemler bittikten sonra ise proxy nesnesinin ömrünü sonlandır.</li>
</ol>
<h1>ChannelFactory Kullanımı</h1>
<p>Aynı örneğin <strong>ChannelFactory</strong> tipi ile olan kullanımı ise aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using Student.clcls;
using System;
using System.ServiceModel;
namespace Student
{
class Program
{
static void Main(string[] args)
{
#region Channel Factory kullanımı
ChannelFactory<IMathService> factory= new ChannelFactory<IMathService>("BasicHttpBinding_IMathService");
IMathService channel = factory.CreateChannel();
double result = channel.Sum(3, 4);
Console.WriteLine(result.ToString());
((IClientChannel)channel).Close();
#endregion
}
}
}</pre>
<p>İlk olarak <strong>generic</strong> <strong>ChannelFactory</strong> tipinden bir nesne örneklendiğini görüyoruz. Bu nesnenin generic parametresi ise servis sözleşmesini ifade eden <strong>IMathService</strong> <strong>arayüzüdür<em>(Interface)</em></strong>. Nesnenin örneklenmesi sırasında <strong>yapıcı metoda<em>(constructor)</em></strong> parametre olarak <strong>app.config</strong> içerisindeki ilgili <strong>EndPoint</strong> adı verilmektedir. Bu sayede servis için gerekli <strong>AddressBindingContract</strong> bilgileri alınmış olur.</p>
<p>İkinci satırda bir kanal nesnesi örneklendiğini görmekteyiz. Bunun için fabrika tipinin <strong>CreateChannel</strong> metodu kullanılmış durumdadır. <strong>CreateChannel</strong> metodu aslında <strong>generic</strong> olarak <strong>ChannelFactory</strong> örneklenmesi sırasında verilen arayüzün taşıyabileceği bir sınıfın üretiminde kullanılmaktadır.</p>
<p>Bundan sonraki kısım ise oldukça basittir. Üretilen <strong>proxy</strong> tipi üzerinden servis metoduna bir çağrı yapılır. Son olarak da oluşturulan kanalın kapatılması işlemi uygulanır.</p>
<h1>Caching</h1>
<p>Çok doğal olarak istemci tarafında kanal nesnesinin üretilmesinin ve iletişimin açılmasının çalışma zamanını ilgilendiren bir maliyeti söz konusudur. Yazımızın başında belirttiğimiz süreç nedeniyle oluşmaktadır. İşte bu sebepten geliştiriciler <strong>ChannelFactory</strong> tipinin özelleştirilmiş hallerini yazmak durumundadır. Lakin bu <strong>WCF 4.5</strong>’e kadar böyleydi. Artık <strong>WCF 4.5</strong> ile birlikte bir kanalın inşa edilmesi işlemi için ön tanımlamaların ön belleklenerek kullanılması söz konusu. Peki ama nasıl?Aşağıdaki örnek kod parçasını inceleyerek devam edelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using Student.clcls;
using System;
using System.ServiceModel;
namespace Student
{
class Program
{
static void Main(string[] args)
{
#region Caching Kullanımı
ClientBase<IMathServiceChannel>.CacheSetting = CacheSetting.AlwaysOn;
for (int i = 0; i < 5; i++)
{
MathServiceClient client = new MathServiceClient(
new BasicHttpBinding()
, new EndpointAddress("http://localhost:54837/MathService.svc")
);
double result = client.Sum(i, 5);
// İlk kullanımda kanal bilgisi cache' lenmiş durumda. Dolayısıyla sonraki çağrıda maliyet minimuma indirgenmiş olacak.
Console.WriteLine("{0}", result.ToString());
}
#endregion
}
}
}</pre>
<p>Caching ile ilişkili ayarlamaları yapmak için <strong>ClientBase<T></strong> tipine ait <strong>CacheSettings</strong> özelliğinden yararlanılmaktadır. Dikkat edileceği üzere söz konusu tipin kullanımı sırasında <strong>IMathServiceChannel</strong> parametre olarak verilmiştir.<em>(I<strong>MathServiceChannel </strong>içeriğine bakıldığında bir <strong>IClientChannel</strong> türevi olduğu görülebilir</em><em>)</em></p>
<p>Kodun bundan sonraki kısımlarında ise <strong>MathServiceClient</strong> sınıfının örneklendiğini görüyoruz. <strong>Binding</strong> ve <strong>Endpoint</strong> bilgileri ile oluşturulan nesne üzerinden de servis metoduna çağrıda bulunulmaktadır. <strong>for</strong> döngüsü nedeniyle aynı <strong>proxy</strong> tipinin bir kaç kez üretimi söz konusudur. İşte bu üretimlerin ilkinde <strong>ClientBase<T></strong> ile belirtilen ayar nedeniyle bir ön bellekleme işlemi söz konusudur.</p>
<p>Aslında <strong>proxy</strong> tipi olarak üretilen <strong>MathServiceClient</strong> sınıfı, generic <strong>ClientBase<TChannel> abstract </strong>sınıfından türemektedir. <strong>svcutil</strong> aracı <strong>proxy</strong> tipini bu şekilde üretmektedir<em>(Doğal olarak <strong>Add Service Reference</strong> için de aynı durum söz konusudur)</em></p>
<p><a href="https://www.buraksenyurt.com/pics/cfcache_2.png"><img style="margin: 4px 0px; display: inline;" title="cfcache_2" src="/pics/cfcache_2_thumb.png" alt="cfcache_2" width="618" height="542" /></a></p>
<p>Bu sınıf açılımı nedeniyle <strong>CacheSetting</strong> özelliği <strong>proxy</strong> tipi üzerinden de doğrudan uygulanabilir.</p>
<h1>CacheSetting Modları</h1>
<p><strong>CacheSetting</strong> özelliğine atanabilecek üç değer bulunmaktadır. <strong>AlwaysOn</strong>, <strong>Default</strong> ve <strong>AlwaysOff</strong>. Bu değerler ve aralarındaki farklılıklar aşağıdaki tabloda özetlenmeye çalışılmıştır.</p>
<table style="width: 640px;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td valign="top" width="162"><strong>CacheSetting Değeri</strong></td>
<td valign="top" width="478"><strong>Anlamı</strong></td>
</tr>
<tr>
<td valign="top" width="162"><strong>Default</strong></td>
<td valign="top" width="478">Aynı Application Domain içerisinde olmak kaydıyla, konfigurasyon dosyasında tanımlanmış olan EndPoint bilgilerinden üretilmiş ClientBase örnekleri için Caching özelliği etkinleştirilir. <br /> <br />Bu Application Domain içerisinde oldukları halde programatik olarak üretilen ClientBase türevli tipler ise Caching’ e dahil edilmezler. <br /> <br /><em>Ayrıca Credential bilgisi gibi Security özellikleri söz konusu olan ClientBase türevli örnekler de Caching dışında tutulurlar. Nitekim security bilgileri sürekli olarak değişebilir ve Cache tutulması bu anlamda doğru değildir.</em></td>
</tr>
<tr>
<td valign="top" width="162"><strong>AlwaysOn</strong></td>
<td valign="top" width="478">Aynı Application Domain içerisinde yer alan tüm ClientBase türevli tipler için Caching özelliği etkinleştirilir. <br /> <br /><em>Burada dikkat edilmesi gereken nokta security-sensitive bilgiler olması halinde Caching’ in pasifleştirilmeyeceğidir. Default moddakine aykırı bir durum söz konusudur.</em></td>
</tr>
<tr>
<td valign="top" width="162"><strong>AlwaysOff</strong></td>
<td valign="top" width="478">Application Domain içerisindeki ClientBase türevli tipler için Caching özelliği kapatılır.</td>
</tr>
</tbody>
</table>
<p><br />Bu yeni kabiliyet küçük çaplı servis örnekleri göz önüne alındığında pek fark edilmese de, enterprise çözümlerde kullanılan ve üretim maliyetleri de yüksek olan versiyonlar düşünüldüğünde ciddi olarak dikkate alınması gerekmektedir. Tabi burada söz konusu olan modlar arasındaki farklılıklara da bakılmalıdır. Özellikle <strong>security-sensitive</strong> tanımlamalarda <strong>Default</strong> ve <strong>AlwaysOn</strong> modların farklı davranışlar gösterdiği unutulmamalıdır. Konu ile ilişkili daha detaylı bilgiyi <a href="http://msdn.microsoft.com/tr-tr/library/hh314046.aspx" target="_blank">MSDN sayfasından</a> alabilirsiniz. Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2013%2f7%2fChannelFactoryCaching.zip">ChannelFactoryCaching.zip (66,14 kb)</a></p>2014-12-22T19:00:00+00:00windows communication foundationchannelchannel factorycachingwcf 4.5service contracticlientchannelclientbasegenericbsenyurtBir WCF(Windows Communication Foundation) servisi ile onun tüketicisi olan istemci arasındaki iletişimde önem arz eden konulardan birisi de kanaldır(Channel). Bu kanalın oluşturulması görevini ChannelFactory tipi üstlenmektedir. İstemci açısından bakıldığında bir kanalın oluşturulması aslında servisin bir Proxy tipinin üretilmesi ve uzak metod çağrıları için gerekli iletişim ortamının sağlanması anlamına gelmektedir. Bir kanal esas itibariyle EndPoint odaklı üretilir. Dolayısıyla WCF' in ABC'si olarak nitelendirilen Address Binding Contract üçlemesi üzerine inşa olunur(ki bu da WCF Service EndPoint tanımıdır)https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=046c6f71-ae63-4d2b-b5ef-504f6e49932e1https://www.buraksenyurt.com/trackback.axd?id=046c6f71-ae63-4d2b-b5ef-504f6e49932ehttps://www.buraksenyurt.com/post/WCF-ChannelFactory-Tipi-icin-Caching-Kullanimi#commenthttps://www.buraksenyurt.com/syndication.axd?post=046c6f71-ae63-4d2b-b5ef-504f6e49932ehttps://www.buraksenyurt.com/post/WCF-WebHttp-Service-JSON-jQuery-Ajax-ve-CORS-ile-Yeni-Bir-MaceraWCF WebHttp Service, JSON, jQuery, Ajax ve CORS ile Yeni Bir Macera2014-09-03T08:27:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/browser_wars.jpg"><img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border: 0px;" title="browser_wars" src="/pics/browser_wars_thumb.jpg" alt="browser_wars" width="300" height="236" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>Bir süredir şirket içerisinde kullanılacak olan web tabanlı bir .Net uygulamasının geliştirilmesinde görev almaktayım. Uygulama, yürütülen süreç gereği her iterasyon sonunda yeni özellikler eklenmiş ve hataları giderilmiş biçimde Üretim<em>(Production)</em> ortamına taşınmakta.</p>
<p>Projede kaynak sıkıntısı nedeniyle uzun bir süre servis katmanı haricinde kalan arayüz tarafı ile de ilgilenmek zorunda kaldım. Arayüz tarafı ile uğraşırken iş biriminden gelen isteklere göre <strong>CSS<em>(Cascading Style Sheets)</em> </strong>ve bol miktarda <strong>Javascript</strong> kodlamak benim gibi acemiler için epeyce zorlayıcıydı. Lakin en çok zaman kaybettiğim vaka, şirket içinde kullanılmakta olan eski,yeni ve çeşitli tipteki tarayıcıların uyumlu çalışmasının sağlanabilmesiydi. Kimi lokasyonda <strong>Internet Explorer 8</strong>, kimi yerlede <strong>Google Chrome</strong>’ un en güncel sürümü bulunmakta. Hatta global çevrimde <strong>Firefox</strong> standart olarak her bilgisasyarda yüklü geliyor.</p>
<p>Şunu fark ettim ki, tarayıcı savaşları makalelerde okuduğumuzdan çok daha ciddi boyutta. Havada uçuşan standartları farklı farklı yorumlama biçimleri nedeniyle her tarayıcıya uygun standart çözümler üretmek gerçekten zormuş. En azından benim için <img class="wlEmoticon wlEmoticon-smile" style="border-style: none;" src="/pics/wlEmoticon-smile_105.png" alt="Smile" /> Basit bir <strong>CSS</strong>' in <strong>Internet Explorer'</strong> da sorunsuz çalışırken <strong>Chrome</strong>' da problem çıkarttığına, <strong>Chrome</strong>' da dertsiz işleyen bir <strong>Ajax Control Toolkit </strong>kontrolünün, <strong>Firefox</strong>’ un eski bir sürümünde hiç çalışmadığına şahit oldum. Hal böyle olunca çalışma zamanında, tarayıcıların debug kabiliyetleri ile de haşır neşir olmak zorunda kaldım. Sıkıcı mıydı? Hayır <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_216.png" alt="Winking smile" /> Aksine benim için farklı ve değer katan deneyimlerdi. İşte bu düşünceler geçtiğimiz günlerde yine internet üzerinde bir şeyler araştırıp öğrenmeye çalışırken kendimi farklı bir macera içerisinde buldum. Sonunda bunu kaleme almanın yararlı olacağını düşündüm ve işte buradayım.</p>
<h1>Senaryo</h1>
<p>Bu yazımızda bir kavram ve terim cümbüşü içerisinde yer alacağımızı söyleyebilirim. Yazacağımız basit bir <strong>WCF</strong> servisini öncelikle <strong>REST</strong> tabanlı çalışır hale getireceğiz. Ardından söz konusu servise <strong>jQuery</strong> kütüphanesinden yararlanarak bir <strong>Ajax</strong> çağrısı gerçekleştireceğiz. Temel hedefimiz ise <strong>HTTP</strong> <strong>Post</strong> metoduna göre bir içeriği tarayıcı üzerinden servise göndermek olacak. Lakin <strong>JSON<em>(JavaScript Object Notation)</em></strong> tipinden bir nesne kullanacağız. Kabaca aşağıdaki çizelge de görülen durumun söz konusu olduğunu söyleyebiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_7_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_7" src="/pics/restJquery_7_thumb_1.png" alt="restJquery_7" width="605" height="302" /></a></p>
<p>Bu toplu senaryo aslına bakılırsa günümüzün popüler pek çok web tabanlı uygulamasında kullanılabilecek türden. Haydi gelin parmaklarımızı sıvayalım...</p>
<h1>Servis Tarafının Geliştirilmesi</h1>
<p>İlk olarak aşağıdaki servis sözleşmesini içeren bir <strong>WCF Service Application</strong> projesi açarak yola çıkabiliriz. Söz konusu projede <strong>IProductService</strong> isimli bir sözleşme<em>(Service Contract)</em> yer alacak.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
using System.ServiceModel.Web;
namespace AzonServices
{
[ServiceContract]
public interface IProductService
{
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "AddProduct")]
string PostProduct(Product NewProduct);
}
}</pre>
<p>Senaryomuzda sadece <strong>HTTP</strong> <strong>Post</strong> metodunu ele almak istediğimizden basit bir operasyon söz konusu. Önemli olan servis operasyonunun <strong>WebInvoke</strong> niteliği<em>(attribute)</em> ile işaretlenmiş olmasıdır. <strong>WebInvoke</strong> niteliği bu operasyonun <strong>HTTP</strong> tabanlı taleplere cevap verecek şekilde kullanılabileceğini ifade etmektedir.</p>
<p>Niteliğin içerisinde dikkat edileceği üzere bir kaç özelliğin set edildiği görülmektedir. <strong>Method</strong> özelliğine atanan değer ile, operasyonun <strong>HTTP</strong> <strong>Post</strong> taleplerine cevap vereceği belirtilmektedir. <strong>RequestFormat</strong> ve <strong>ResponseFormat</strong> özellikleri ile operasyona gelen ve istemcilere cevap olarak dönen içeriklerin <strong>JSON</strong> formatında serileştirileceği ifade edilir. Son olarak bir <strong>Uri</strong> şablonu atanmıştır. <strong>UriTemplate'</strong> e atanan <strong>AddProduct</strong> ifadesi, istemci tarafının göndereceği<strong> HTTP Post</strong> talebinde kullanılacaktır.</p>
<p>Servis metodu <strong>Product</strong> tipinden bir nesne örneğini alıp geriye <strong>string</strong> tipte içerik döndürecek şekilde tasarlanmıştır. <strong>Product</strong> tipi oldukça basit bir içeriğe sahiptir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace AzonServices
{
public class Product
{
public int ProductId { get; set; }
public string Title { get; set; }
public decimal ListPrice { get; set; }
}
}</pre>
<p>Gelelim <strong>ProductService.svc</strong> öğesinin kodlarına.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
namespace AzonServices
{
public class ProductService
: IProductService
{
List<Product> productList = new List<Product>();
public string PostProduct(Product NewProduct)
{
productList.Add(NewProduct);
return Guid.NewGuid().ToString();
}
}
}</pre>
<p><strong>ProductService.svc</strong> içerisinde çok özel bir kod parçası yoktur. Sadece generic bir <strong>List<Product></strong> örneğine, <strong>PostProduct</strong> metoduna gelen <strong>Product</strong> örneğinin eklenmesi işlemi icra edilmektedir. Test sırasında istemcinin doğru bir cevap aldığını kolayca tespit etmek adına metod geriye benzersiz bir <strong>Guid</strong> değeri döndürmektedir.</p>
<h1>EndPoint Bildirimi</h1>
<p>Servis tarafı için önem arz eden konulardan birisi de <strong>EndPoint</strong> tanımlamasıdır. Servis, <strong>REST</strong> tabanlı olacak şekilde çalışabilmelidir. <strong>WCF</strong> bu noktada <strong>WebHttpBinding</strong> isimli <strong>Binding</strong> tipini sağlamaktadır. Bu sebepten<strong> web.config</strong> içerisinde gerekli tanımlamaların yapılması gerekmektedir. Aynen aşağıda görüldüğü gibi.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="AzonServices.ProductService">
<endpoint address=""
binding="webHttpBinding"
contract="AzonServices.IProductService" behaviorConfiguration="webBehavior"></endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration></pre>
<p><strong>endpoint</strong> elementi içerisinde yer alan <strong>binding</strong> niteliğine <strong>webHttpBinding</strong> atanması haricinde bir de <strong>HTTP</strong> davranışının verilmesi söz konusudur. Bunun için dikkat edileceği üzere bir <strong>endPoint</strong> <strong>Behavior</strong> tanımlaması yapılmış ve <strong>webHttp</strong> değeri eklenmiştir. Eğer bir problem yoksa <strong>ProductService.svc</strong> dosyasının tarayıcı üzerinde aşağıdaki gibi açılması gerekir.</p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_1_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_1" src="/pics/restJquery_1_thumb_1.png" alt="restJquery_1" width="640" height="348" /></a></p>
<blockquote>
<p>Servisin Metadata Publishing özelliği kapalıdır. Bilindiği üzere <strong>REST</strong> tabanlı servislere HTTP protokolü ve metodları ile erişilmektedir. Bu yüzden istemci tarafında bir Proxy nesnesi kullanılmasına gerek yoktur.</p>
</blockquote>
<h1>İstemci Tarafı</h1>
<p>Gelelim istemci uygulamanın geliştirilmesi. Servis tüketicisi bir Web uygulaması olarak inşa edilecektir. Detayları bir kenara bırakıp asıl konuya odaklanmak istediğimizden <strong>Asp.Net Empty Web Application</strong> projesi bizim için biçilmiş kaftandır. <strong>Web</strong> uygulamamızda <strong>jQuery</strong> kullanacağımızdan en azından ilgili <strong>javascript</strong> kütüphanesinin eklenmesi gerekir.</p>
<blockquote>
<p>Bunun için <a href="http://jquery.com/download/">http://jquery.com/download/</a> adresine giderek istediğiniz bir sürümü seçebilirsiniz. Sürüm seçiminde bu sayfada yazılan notlara dikkat etmenizi öneririm. Eğer kurumunuzun tarayıcılar ile ilişkili bazı kuralları varsa ve özellikle eski tarayıcılar ile çalışıyorlarsa uygun jQuery kütüphanesinin seçilmesi doğru olacaktır.</p>
</blockquote>
<p>Ben örnek projemizde <strong>jQuery-2.1.0.min.js</strong> sürümünü kullanmayı tercih ettim. İlgili <strong>Script</strong> dosyasını projeye ekledikten sonra <strong>Default.aspx</strong> sayfasını aşağıdaki gibi geliştirebiliriz.</p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ClientApp.Default" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>REST Service Test</title>
<meta http-equiv="X-UA-Compatible" content="IE=10" />
</head>
<body>
<script type="text/javascript" src="Scripts/jquery-2.1.0.min.js">
</script>
<script type="text/javascript">
function AddNewProduct() {
var product = {
"ProductId": 1220,
"Title": "ElCiii 4580 Laptop",
"ListPrice": "1499"
};
$.ajax({
type: "POST",
url: "http://localhost:61954/ProductService.svc/AddProduct",
data: JSON.stringify(product),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data, status, xmlRequest) {
alert("JSON içeriği "+JSON.stringify(product)+". "+data + " numaralı ürün eklenmiştir");
},
error: function (xmlRequest,status,errorThrown) {
alert(xmlRequest.responseText);
}
});
}
</script>
<form id="form1" runat="server">
<div>
<input type="button" value="Add New Product" onclick="AddNewProduct()" />
</div>
</form>
</body>
</html></pre>
<h1>Çalışma Şekli</h1>
<p>Şimdi web sayfasını biraz inceleyelim. Burada koşullara ve şartlara göre uygulanmış bazı hileler de bulunmaktadır. İlk olarak projeye ilave edilmiş <strong>jQuery</strong> kütüphanesinin kullanılacağı belirtilmiştir. <strong>Form</strong> üzerinde <strong>button</strong> tipinden bir <strong>input</strong> elementi yer almaktadır. İstemci tarafında bu buton tıklandığında ise <strong>AddNewProduct</strong> isimli <strong>javascript</strong> fonksiyonu çalıştırılmaktadır. Peki fonksiyon içerisinde neler olmaktadır?</p>
<p>İlk olarak <strong>product</strong> isimli bir tip oluşturulduğunu ve <strong>ProductId</strong>, <strong>Title</strong>, <strong>ListPrice</strong> özelliklerine bir takım değerler atandığını görebiliriz. Bu tanımlamayı takip eden satırda ise <strong>ajax</strong> fonksiyon çağrısı gerçekleştirilmektedir. <strong>ajax</strong> fonksiyonun pek çok parametresi bulunmaktadır. Örnekte <strong>HTTP Post</strong> çağrısı gerçekleştirileceğinden <strong>type</strong> özelliğine <strong>POST</strong> değeri atanmıştır. <strong>url</strong> özelliği tahmin edileceği üzere <strong>HTTP</strong> <strong>Post</strong> talebinin gönderileceği WCF Servis adresini işaret etmektedir. Bu adres tanımında yer alan <strong>AddProduct</strong> son ekine ayrıca dikkat edilmelidir.</p>
<p>Hatırlanacağı üzere bu bilgi servis operasyonunun <strong>WebInvoke</strong> niteliğinde belirtilmiştir. data kısmında gerçekleştirilen <strong>stringify</strong> çağrısı, parametre olarak aldığı <strong>product</strong> nesne örneğini <strong>JSON</strong> formatına çevirmek üzere kullanılır. Böylece servise gönderilecek olan <strong>JSON </strong>içeriği oluşturulur. <strong>contentType</strong> özelliğine atanan değer ile içerik tipinin <strong>JSON </strong>olacağı ve karakter seti olarak <strong>utf-8</strong> standardının kullanılacağı belirtilmektedir. <strong>dataType</strong> özelliği <strong>POST</strong> işlemi sırasında kullanılan veri tipinin <strong>JSON </strong>olduğunu işaret eder. <strong>success</strong> ve <strong>error</strong> değişkenleri tahmin edileceği üzere çağrının başarılı veya hata olması durumlarnda devreye giren fonksiyonları taşımaktadır. Her iki fonksiyon da standart olarak <strong>XmlHttpRequest</strong> tipini kullanır.</p>
<p>Biz örneğimizde bu fonksiyonellikler içerisinde önemli bir iş yapmıyoruz. Sadece çağrının başarılı olması halinde gönderilen <strong>JSON</strong> içeriğini ve servisden gelen <strong>GUID</strong> değerini bir mesaj kutusu içerisine gösteriyoruz. Pek tabi gelen içeriğin sayfa üzerinde yer alan bir takım kontrollere basılması da düşünülebilir.</p>
<p>Web sayfasında dikkat edilmesi gereken noktalardan birisi de title elementinin hemen altında kullanılan meta tag' dir.</p>
<p><strong><meta http-equiv="X-UA-Compatible" content="IE=10" /></strong></p>
<p>Bunu şöyle ifade etmeye çalışalım. Örneği gerçekleştirdiğimiz sistemde <strong>Internet Explorer</strong>' ın <strong>10</strong> sürümü bulunmakta ve web sayfasının aslında <strong>IE Compatibility Mode</strong>' da çalıştığı görülmektedir. Nitekim bu bildirimin <strong>meta tag</strong> olarak bildirilmemesi halinde istemci tarafında bir <strong>script</strong> hatası ile karşılaşılmaktadır.</p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_2_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_2" src="/pics/restJquery_2_thumb_1.png" alt="restJquery_2" width="432" height="279" /></a></p>
<blockquote>
<p>Bu sorun IE 11' de kendini göstermeyebilir. Ya da jQuery kütüphanesinin daha eski bir sürümü böyle bir hatayı oluşturmayabilir. Hatta bu meta tag açık olduğunda Document Mode' un IE 9, 8 ve 7 olduğu durumlarda kütüphanenin aynı hatayı vermeye devam ettiği de tespit edilmiştir. Bu tarayıcıları anlamak hakikaten zor <img class="wlEmoticon wlEmoticon-confusedsmile" style="border-style: none;" src="/pics/wlEmoticon-confusedsmile_33.png" alt="Confused smile" /></p>
</blockquote>
<h1>Uyumluluk Sonrası Chrome Öncesi ve CORS</h1>
<p>Örneğimizi <strong>Internet Explorer</strong> ile<em>(en azından sistemde var olan sürümü ile)</em> uyumlu hale getirdik diyebiliriz. <strong>Default.aspx</strong> sayfasında <strong>Add New Product</strong> başlıklı butona bastığımızda aşağıdakine benzer bir mesaj kutusu ile karşılaşmamız gerekmektedir.</p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_3_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_3" src="/pics/restJquery_3_thumb_1.png" alt="restJquery_3" width="464" height="295" /></a></p>
<p>Görüldüğü üzere başarılı bir şekilde servis çağrısı yapılmıştır. <strong>JSON</strong> içeriği üretilmiş ve servisden benzersiz bir <strong>GUID</strong> değeri elde edilmiştir. Ne var ki örnek <strong>Chrome</strong>' da çalışmamaktadır <img class="wlEmoticon wlEmoticon-surprisedsmile" style="border-style: none;" src="/pics/wlEmoticon-surprisedsmile_6.png" alt="Surprised smile" /> <em>(Yine örneğin geliştirildiği makinedeki tarayıcı sürüm için böyle bir durum oluştuğunu ifade edelim) </em></p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_4_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_4" src="/pics/restJquery_4_thumb_1.png" alt="restJquery_4" width="345" height="118" /></a></p>
<p>Pek de sevimli olmayan bir hata mesajı <img class="wlEmoticon wlEmoticon-sadsmile" style="border-style: none;" src="/pics/wlEmoticon-sadsmile_16.png" alt="Sad smile" /> Eğer Chrome tarafında <strong>debug</strong> işlemi uygulanırsa aşağıdaki gibi bazı hataların oluştuğuna şahit olunur. İşte buton tıklandıktan sonraki durum.</p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_5_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_5" src="/pics/restJquery_5_thumb_1.png" alt="restJquery_5" width="621" height="477" /></a></p>
<p>3 hata mesajı söz konusudur. Hata mesajlarının ikisi <strong>jQuery</strong> kütüphanesinden gelmektedir ama ana fikir söz konusu metod çağrısına izin verilmemiş olmasıdır. Aslında dikkatli gözler şunu hemen fark edecektir. Web uygulamasının host ediliği <strong>port</strong> ile WCF Service uygulamasının host edildiği <strong>port</strong> birbirinden farklıdır. Bu <strong>Cross Domain</strong> çağrı <strong>Chorme</strong> tarafından işlenmemiştir. Çözüm olarak<em>(ki burada istediğimiz sadece servisin Chrome üzerinden IE' de olduğu gibi çağırılabildiğini görmektir)</em> ilgili servisin ve web uygulamasının aynı domain' de host edilmesi sağlanabilir. Yani <strong>IIS</strong> altına atılmaları halinde her hangibir sorun olmadan çağırılabildikleri görülecektir.</p>
<blockquote>
<p>Modern tarayıcıların bu tip Cross Domain referans çağrılarına izin vermediği bilinmektedir. Servislerin bu noktada çözüm olarak istemciden gelecek olan bu tip Header' ları kabul edecek şekilde tesis edilmesi gerekmektedir. Bu sıkıntı CROS olarak isimlendirilmiştir. Dolayısıyla servis tarafı CORS <em>(Cross-Origin Resource Sharing)</em> özelliğini desteklemelidir. Bir başka deyişle servisin istemciden gelen Header bilgisine göre POST talebini kabul edecek şekilde ayarlanması sorunu çözecektir.</p>
</blockquote>
<h1>Sorunu Büyüttük</h1>
<p>Görüldüğü üzere yeni bir mücade ile karşı karşıyayız. <strong>WCF</strong> servisini <strong>CORS</strong> destekli hale getirmek çözümlerden bir tanesi. Ancak oldukça zahmetli olan bu yola yazımızda değinmeyeceğiz. Yine de ilgilenler <a href="http://enable-cors.org/server_wcf.html">http://enable-cors.org/server_wcf.html</a> adresine uğrayabilirler. Daha basit bir çözüm olarak <strong>WCF Service Application'</strong> ın aslında bir Web uygulaması gibi davranış gösterdiğini düşünerek hareket edeceğiz. Dolayısıyla bir <strong>global.asax</strong> dosyası ve gelen uygulamaya gelen taleplerin yakalandığı olay metodları söz konusudur. Bu noktada Application_BeginRequest metodu içeriğini aşağıdaki kod parçasında görüldüğü gibi yazmamız yeterli olacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type");
HttpContext.Current.Response.End();
}
}</pre>
<p><strong>BeginRequest</strong> metodu tahmin edileceği üzere <strong>WCF</strong> servisini host ettiğimiz uygulamaya gelecek her talep için devreye girecektir. <strong>jQuery</strong> ile gerçekleştirdiğimiz <strong>ajax</strong> çağrısında <strong>ContentType</strong> <strong>Header</strong> bilgisi kullanılmış ve <strong>POST</strong> metoduna göre talep de bulunulmuştur. <strong>BeginRequest</strong> metodunun yaptığı pratikte bu şekilde gelen istekleri geri çevirmemek ve istemci tarafına da uygun olan <strong>Header</strong> bilgisini göndermektir. Söz konusu değişiklik sonrası uygulamanın <strong>Chrome</strong> üzerinde de sorunsuz bir şekilde çalışabildiği görülecektir.</p>
<p><a href="https://www.buraksenyurt.com/pics/restJquery_6_1.png"><img style="margin: 4px 0px; display: inline;" title="restJquery_6" src="/pics/restJquery_6_thumb_1.png" alt="restJquery_6" width="485" height="195" /></a></p>
<h1>Eksikler</h1>
<p>Elbette senaryomuzda önemli eksiklikler bulunmaktadır. Örneğin,</p>
<ul>
<li>Servis tarafının bir sertifika ile çağırılabileceği durumlarda CORS için nasıl aksiyonlar almak gerekir?</li>
<li>Son uygulanan pratik, tüm tarayıcılar da çalışmakta mıdır? Örneğin <strong>Firefox</strong>' ta. Peki ya mobil cihazda bulunan <strong>Native</strong> kodla geliştirilmiş bir Browser bileşeninde?</li>
<li>Acaba Windows Forms içerisinde kullanına WebBrowser gibi kontrollerde sonuç nasıl olacaktır?</li>
<li>Peki <strong>HTTP</strong> <strong>Get</strong> ile bir <strong>JSON</strong> veri kümesi istemci tarafına nasıl çekilebilir?</li>
<li>Ya veri göndermek için sayfa üzerine konacak kontrollerden nasıl yararlanılabilir?</li>
</ul>
<p>Bu soruların çözümünü, araştırmasını ve uygulanmasını siz değerli okurlarıma bırakıyorum. Bu mücadeleler inanın size önemli saha tecrübeleri kazandıracaktır. Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2014%2f2%2fHowTo_RestPostJQuery.rar">HowTo_RestPostJQuery.rar (111,76 kb)</a></p>2014-09-03T08:27:00+00:00wcfweb http servicesrestrest servicesjsonjqueryajaxcorsbsenyurtBu yazımızda bir kavram ve terim cümbüşü içerisinde yer alacağımızı söyleyebilirim. Yazacağımız basit bir WCF servisini öncelikle REST tabanlı çalışır hale getireceğiz. Ardından söz konusu servise jQuery kütüphanesinden yararlanarak bir Ajax çağrısı gerçekleştireceğiz. Temel hedefimiz ise HTTP Post metoduna göre bir içeriği tarayıcı üzerinden servise göndermek olacak. Lakin JSON(JavaScript Object Notation) tipinden bir nesne kullanacağız. Kabaca aşağıdaki çizelge de görülen durumun söz konusu olduğunu söyleyebiliriz.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=e998c39f-2d74-4710-8734-952e459637d13https://www.buraksenyurt.com/trackback.axd?id=e998c39f-2d74-4710-8734-952e459637d1https://www.buraksenyurt.com/post/WCF-WebHttp-Service-JSON-jQuery-Ajax-ve-CORS-ile-Yeni-Bir-Macera#commenthttps://www.buraksenyurt.com/syndication.axd?post=e998c39f-2d74-4710-8734-952e459637d1https://www.buraksenyurt.com/post/AspNete28099-ten-HTTPS-Tabanlc4b1-WCF-Cagrc4b1sc4b1-GerceklestirmekAsp.Net’ ten HTTPS Tabanlı WCF Çağrısı Gerçekleştirmek2014-08-13T12:00:00+00:00bsenyurt<p><a><img style="margin: 4px 0px; display: inline; float: right;" title="381eed443562d941546485cc9e2decf4_1316198153" src="/pics/381eed443562d941546485cc9e2decf4_1316198153_thumb.jpg" alt="381eed443562d941546485cc9e2decf4_1316198153" width="207" height="243" align="right" /></a>Merhaba Arkadaşlar,</p>
<p>Özel Ajan Oso! Son yılımda Disney Channel’ de sıklıkla maruz kaldığım bir çizgi karakter. Aslında bu sakar ve bir o kadar da maharetli ve sevimli çizgi dizi kahramının görevi son derece basit. Sadece 3 adımda çocuklara yol gösterici nitelikte yardımcı olmaya çalışmak.</p>
<p>Ajanımızın dizi de bir de yöneticisi var. Aynı Mission Impossible’ da olduğu gibi. Onun adı “Bay Dost”</p>
<p>Her bölüm Özel Ajan Oso’ ya bir görev veriliyor. Söz gelimi çocuklardan birisi yanlışlıkla kumbarasının bir ayağını kırmış olsun. Bunu nasıl tamir eder? 3 adımda. Dizi de olay şöyle ilerler.</p>
<p><em>Adım 1 : Kırılan kısma tutkal sür</em></p>
<p><em>Adım 2 : Kumbara ile kırılan kısmı birleştir</em></p>
<p><em>Adım 3 : 7 saniye boyunca birleşik şekilde tut</em></p>
<p>gibi</p>
<p>Bazen biz geliştiriciler de bir işi icra edebilmek adına bu şekilde basit ve az sayıda adıma ihtiyaç duyarız. İşte bugünkü makalemizde kendimizi Özel Ajan Oso yerine koyacak ve şu senaryoyu gerçekleştirmeye çalışıyor olacağız.</p>
<h1><strong>Adım 0 : Senaryo</strong></h1>
<p><strong>Development</strong> ortamında geliştirme yapmaktayız. <strong>IIS</strong> üzerinde host edilen bir <strong>WCF</strong> Servis uygulamamız var. Bu servis uygulaması <strong>WS</strong> <strong>Security</strong> standartlarında ve <strong>SSL</strong> tabanlı bir hizmet sunmakta. Bir başka deyişle servise <strong>https</strong> üzerinden talep gönderebiliyoruz. Servisin <strong>WSDL</strong> içeriğinin elde edilebildiği adres de aslında <strong>HTTPS</strong> tabanlı.</p>
<p>İstemci tarafı ise <strong>Asp.Net</strong> tipinden bir web uygulaması. Bu uygulamanın söz konusu servise <strong>HTTPS</strong> tabanlı olarak talep gönderebilmesi ve cevap alabilmesi isteniyor. <strong>Development</strong> ortamında çalışıldığından gerçek bir sertifika yerine, <strong>Microsoft’</strong> un test amaçlı <strong>X509</strong> sertifikasının kullanılması planlanıyor.</p>
<p>O halde ne duruyoruz! Haydi bilgisayar başına.</p>
<h1><strong>Adım 1 : WCF Servis Uygulamasını Oluştur</strong></h1>
<p>Öncelikli olarak bir <strong>WCF Service Application</strong> projesi oluşturarak işe başlayabiliriz. <strong>Test</strong> amaçlı kodlar içerecek olan servisin dahilindeki tiplerden ziyade konfigurasyon tarafında yapılan ayarlar senaryomuz gereği çok daha önemli. İlk olarak sınıf diagramımıza bakalım ve bizim için gerekli tipleri üretelim.</p>
<p><a><img style="margin: 4px 0px; display: inline;" title="wcfhttps_8" src="/pics/wcfhttps_8_thumb.png" alt="wcfhttps_8" width="350" height="451" /></a></p>
<p><strong>Servis sözleşmesi;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ServiceModel;
namespace EmployeeService
{
[ServiceContract]
public interface IEntryService
{
[OperationContract]
Employee InsertEmployee(Employee newEmployee);
}
}</pre>
<p>Bir <strong>Employee</strong> tipinin sembolik olarak üretimi ve doldurulan Id değeri ile geri döndürülmesini üstlenen servis operasyonu söz konusudur.</p>
<p><strong>Sözleşme uygulayıcısı;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
namespace EmployeeService
{
public class EntryService
: IEntryService
{
public Employee InsertEmployee(Employee newEmployee)
{
newEmployee.EmployeeId = 1903;
return newEmployee;
}
}
}</pre>
<p><strong>Employee tipi</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace EmployeeService
{
public class Employee
{
public int EmployeeId { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public int Level { get; set; }
}
}</pre>
<p>ve en önemli kısım, servis tarafındaki konfigurasyon içeriği <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_136.png" alt="Winking smile" /></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="TransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="EntryServiceBehavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service
name="EmployeeService.EntryService"
behaviorConfiguration="EntryServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://localhost/EmployeeService/"/>
</baseAddresses>
</host>
<endpoint
address="EntryService.svc"
binding="wsHttpBinding"
bindingConfiguration="TransportSecurity"
contract="EmployeeService.IEntryService"
/>
<endpoint
address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange"
/>
</service>
</services>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration></pre>
<p>Senaryomuza göre <strong>WCF</strong> servis uygulamamız <strong>https</strong> tabanlı olarak hizmet veriyor olacak. Bir başka deyişle <strong>WS-I</strong> <strong>HTTP</strong> standartlarını kullanan ve <strong>transport</strong> seviyesinde güvenlik sunan bir servis çalışması söz konusu. Bu nedenle <strong>wsHttpBinding</strong> tipinin kullanılması, servisin iletişim sırasında kullanacağı güvenlik çeşidinin <strong>transport</strong> olarak belirlenmesi gerekiyor. Ayrıca servisin <strong>metadata</strong> bilgisinin de <strong>https</strong> üzerinden elde edilmesini istediğimizden, <strong>mexHttpsBinding</strong> bağlayıcı tipinin kullanılması ve davranışsal özelliklerde <strong>httpsGetEnabled</strong> niteliğinin <strong>true</strong> olarak set edilmesi gerekiyor.</p>
<blockquote>
<p>Bu arada servis uygulamasının IIS üzerinde host edilecek şekilde oluşturulduğunu ifade edelim. İlk etapta base adresin https olarak belirtilmesine rağmen IIS tarafındaki Virtual Directory’ nin HTTP tabanlı çalıştığını düşünüyoruz. Bu haliyle servisi çalıştırmaya kalkarsak, sertifikasyon ile ilişkili hatalar almamız muhtemeldir. Dolayısıyla çözüm olarak bir test sertfikası üretecek, web uygulamasının http için oluşturulan Virtual Directory’ sini IIS Manager yardımıyla ele alacak ve SSL kullanımını etkinleştireceğiz.</p>
</blockquote>
<h1><strong>Adım 2 : Makecert ile Test Sertifikasının Oluşturulması</strong></h1>
<p><strong>Windows SDK</strong> ile birlikte gelen <strong>makecert</strong> aracını kullanarak <strong>X509</strong> tabanlı test sertifikalarının oluşturulması mümkündür. Özellikle <strong>development</strong> süreçlerinde bu aracı kullanarak <strong>SSL</strong> tabanlı senaryoların ele alınması son derece kolaydır. Senaryomuz için örnek bir test sertifikasını aşağıdaki ekran görüntüsünde olduğu gibi basitçe üretebiliriz.</p>
<blockquote>
<p>makecert –r –pe –n “CN=makineadı" –b 01/01/2000 –e 01/01/2100 –eku 1.3.6.1.5.5.7.3.1 –ss my –sr localmachine –sky exchange –sp “Microsoft RSA SChannel Cryptographic Provider” –sy 12</p>
</blockquote>
<p><a href="https://www.buraksenyurt.com/pics/wcfhttps_1.png"><img style="margin: 4px 0px; display: inline;" title="wcfhttps_1" src="/pics/wcfhttps_1_thumb.png" alt="wcfhttps_1" width="600" height="109" /></a></p>
<h1><strong>Adım 3 : IIS Tarafında SSL Kullanımını Etkinleştirmek</strong></h1>
<p><strong>Https</strong> tabanlı iletişimi <strong>IIS</strong> üzerinde oluşturulan web sayfalarında uygulayabilmemiz için öncelikli olarak site seviyesinde <strong>SSL</strong> kullanımının etkinleştirilmiş olması gerekmektedir. Bunun için <strong>https</strong> tipinin <strong>Bindings</strong> olarak ilave edilmesi yeterli olacaktır. <strong>SSL Settings-> Bindings –> Add</strong> kısmından aşağıdaki ekran görüntüsünde yer alan adımları takip ederek işlemlerimize devam edelim.</p>
<p><a><img style="margin: 4px 0px; display: inline;" title="wcfhttps_3" src="/pics/wcfhttps_3_thumb.png" alt="wcfhttps_3" width="638" height="669" /></a></p>
<p><strong>https</strong> tipinin eklenmesi sırasında bir de <strong>SSL</strong> sertfikası sorulacaktır. Bu sertifikaların seçimi sırasında 2nci adımda üretilen sertifikanın da listelendiğini görebiliriz.</p>
<p><a><img style="margin: 4px 0px; display: inline;" title="wcfhttps_5" src="/pics/wcfhttps_5_thumb.png" alt="wcfhttps_5" width="406" height="220" /></a></p>
<h1><strong>Adım 4 : Publish Edilmiş Virtual Directory için SSL Etkinleştirilmesi</strong></h1>
<p>Artık <strong>http</strong> adresi temelli oluşturulan <strong>Virtual</strong> <strong>Directory</strong> için <strong>SSL</strong> kullanımını etkinleştirebiliriz. Bunun için <strong>WCF</strong> uygulamasının <strong>SSL</strong> <strong>Settings</strong> kısmında aşağıdaki işaretlemeleri yapmamız yeterli olacaktır. <strong>Require SSL </strong>ve istemci tarafı sertifika için <strong>Accept</strong>.</p>
<p><a><img style="margin: 4px 0px; display: inline;" title="wcfhttps_4" src="/pics/wcfhttps_4_thumb.png" alt="wcfhttps_4" width="465" height="308" /></a></p>
<p>Özellikle <strong>Require SSL</strong> seçeneğinin aktif olabilmesi bir önceki adımlarda yaptığımız <strong>IIS</strong> tabanlı <strong>SSL</strong> etkinleştirilmesine bağlıdır.</p>
<blockquote>
<p>Örnekte kullandığımız IIS(Internet Information Services) versiyonu 7.5 dir uygulama Windows 7 Enterprise işletim sistemi üzerinde geliştirilmektedir.</p>
</blockquote>
<h1><strong>Adım 5 : WCF Servis Uygulamasında HTTPS Adres Bilgisinin Kullanılması</strong></h1>
<p>Önceden de belirttiğimiz üzere eğer <strong>IIS</strong> tarafında <strong>SSL</strong> tabanlı bir sertifikasyon söz konusu değilse <strong>WCF</strong> uygulamasının da <strong>https</strong> tabanlı bir proje adresini kullanabilmesi söz konusu değildir. Ancak önceki adımlar ile bu sorunu aşmış bulunuyoruz. Dolayısıyla aşağıdaki ekran görüntüsündeki gibi <strong>Project Url</strong> kısmında <strong>https</strong> protokolünü kullanacağımızı belirtebiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/wcfhttps_2.png"><img style="display: inline;" title="wcfhttps_2" src="/pics/wcfhttps_2_thumb.png" alt="wcfhttps_2" width="600" height="502" /></a></p>
<h1><strong>Adım 5.5 : Test</strong></h1>
<p>Ara adımda<strong> EntryService.svc</strong> sayfasını bir tarayıcı üzerinden açmayı deneyebiliriz. Bu durumda aşağıdaki ekran görüntüsüne ulaşmamız gerekmektedir. Dikkat edileceği üzere <strong>https</strong> tabanlı bir açılış söz konusu olmuştur.</p>
<p><a href="https://www.buraksenyurt.com/pics/wcfhttps_6.png"><img style="display: inline;" title="wcfhttps_6" src="/pics/wcfhttps_6_thumb.png" alt="wcfhttps_6" width="558" height="305" /></a></p>
<p>Ayrıca <strong>WSDL(Web Service Description Language)</strong> erişim adreslerinin de <strong>https</strong> tabanlı olduğu rahatlıkla gözlemlenebilir <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_136.png" alt="Winking smile" /></p>
<h1><strong>Adım 6 : İstemci Uygulamaya Servis Referanasının Eklenmesi</strong></h1>
<p>Senaryomuza göre istemci uygulamamız <strong>ASP.Net</strong> tabanlı bir web uygulamasıdır. <strong>Visual Studio</strong> ile bir<strong> Asp.Net Empty Web Application</strong> oluşturarak bu adıma başlayabiliriz. Bundan sonraki en önemli kısım ise servis referansının projeye dahil edilmesidir. <strong>Add</strong> <strong>Service</strong> <strong>Reference</strong> kısmında <strong>https</strong> tabanlı <strong>WSDL</strong> adresine talepte bulunursak, aşağıdaki ekran görüntüsünde yer alan uyarı mesajı ile karşılaşırız.</p>
<p><a href="https://www.buraksenyurt.com/pics/wcfhttps_7.png"><img style="display: inline;" title="wcfhttps_7" src="/pics/wcfhttps_7_thumb.png" alt="wcfhttps_7" width="530" height="514" /></a></p>
<p>Bu iletişim penceresinde <strong>Yes</strong> seçeneğini işaretleyerek ilerleyelim. Sonuç olarak servis tarafına ait <strong>proxy</strong> tipinin istemci tarafında üretildiğini görürüz. <strong>Client</strong> için söz konusu olan konfigurasyon içeriği ise aşağıdaki gibi olacaktır.</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" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEntryService">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint
address=https://domainName.com.tr/EmployeeService/EntryService.svc/EntryService.svc
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IEntryService"
contract="EmployeeRef.IEntryService"
name="WSHttpBinding_IEntryService"
/>
</client>
</system.serviceModel>
</configuration></pre>
<p>Dikkat edileceği üzere <strong>wsHttpBinding</strong> tipine ait güvenlik modu <strong>Transport</strong> olarak gelmiştir. Ayrıca sunucu tarafında belirttiğimiz gibi <strong>clientCredentialType</strong> niteliği <strong>None</strong> olarak atanmıştır.</p>
<h1><strong>Adım 7 : Test Sayfasının Oluşturulması ve Kodlanması</strong></h1>
<p>Bu amaçla aşağıdaki basit Web formunu hazırladığımızı düşünelim.</p>
<p><a><img style="margin: 4px 0px; display: inline;" title="wcfhttps_10" src="/pics/wcfhttps_10_thumb.png" alt="wcfhttps_10" width="308" height="228" /></a></p>
<pre class="brush:html;auto-links:false;toolbar:false" contenteditable="false"><%@ Page Language="C#" AutoEventWireup="true" CodeBehind="NewEmployee.aspx.cs" Inherits="ClientApp.NewEmployee" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td>
Title :
</td>
<td>
<asp:TextBox ID="txtTitle" runat="server" />
</td>
</tr>
<tr>
<td>
First Name :
</td>
<td>
<asp:TextBox ID="txtFirstName" runat="server" />
</td>
</tr>
<tr>
<td>
Middle Name :
</td>
<td>
<asp:TextBox ID="txtMiddleName" runat="server" />
</td>
</tr>
<tr>
<td>
Last Name :
</td>
<td>
<asp:TextBox ID="txtLastName" runat="server" />
</td>
</tr>
<tr>
<td>
Level :
</td>
<td>
<asp:TextBox ID="txtLevel" runat="server" />
</td>
</tr>
<tr>
<td>
</td>
<td>
<asp:Button ID="btnSend" runat="server" Text="Insert new Employee" OnClick="btnSend_Click" />
</td>
</tr>
<tr>
<td colspan="2">
<asp:Label ID="lblResult" runat="server" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html></pre>
<p>Web sayfasından <strong>Employee</strong> tipine ait <strong>Title</strong>, <strong>FirstName</strong>, <strong>MiddleName</strong>, <strong>LastName</strong> ve <strong>Level</strong> bilgileri alınmaktadır. Bu bilgiler aşağıdaki kod parçası ile de sunucuya gönderilmekte ve sonuç olarak sunucu tarafından üretilen <strong>EmployeeId</strong> değeri <strong>Label</strong> bileşenine basılmaktadır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using ClientApp.EmployeeRef;
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace ClientApp
{
public partial class NewEmployee
: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSend_Click(object sender, EventArgs e)
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(IgnoreCertificationError);
EntryServiceClient proxy = new EntryServiceClient("WSHttpBinding_IEntryService");
Employee newEmployee=proxy.InsertEmployee(new Employee
{
FirstName = txtFirstName.Text,
MiddleName = txtMiddleName.Text,
LastName = txtLastName.Text,
Level = Convert.ToInt32(txtLevel.Text),
Title = txtTitle.Text
}
);
lblResult.Text = newEmployee.EmployeeId.ToString();
proxy.Close();
}
public static bool IgnoreCertificationError(object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
}
}</pre>
<p>Kodun belki de en önemli kısmı <strong>ServerCertificateValidationCallback</strong> tipinin kullanılması ve <strong>IgnoreCertificationError</strong> isimli metod içerisinden daima <strong>true</strong> değeri döndürülmesidir. Bunun sebebi aslında bir test sertifikası kullanmamız ve söz konusu sertifikanın validasyona tabi tutulması halinde çalışma zamanı hatası alacak olmamızdır.</p>
<p><a href="https://www.buraksenyurt.com/pics/wcfhttps_11.png"><img style="margin: 4px 0px; display: inline;" title="wcfhttps_11" src="/pics/wcfhttps_11_thumb.png" alt="wcfhttps_11" width="568" height="452" /></a></p>
<p>Bir başka deyişle oluşacak olan hata sürkülase edilmiştir. Malum development ortamında geliştirme yaptığımızdan bu tip görmezden gelmeleri çözümümüze katabiliriz. Birazcık hile yaptık anlayacağınız.</p>
<p>Artık uygulamayı çalıştırıp test edebiliriz. Eğer adımlarımızda bir sorun yoksa aşağıdaki ekran görüntüsünde olduğu gibi <strong>1903</strong> sonucunu alıyor olmamız gerekmektedir.</p>
<p><a href="https://www.buraksenyurt.com/pics/wcfhttps_9.png"><img style="margin: 4px 0px; display: inline;" title="wcfhttps_9" src="/pics/wcfhttps_9_thumb.png" alt="wcfhttps_9" width="341" height="257" /></a></p>
<p><strong>WCF</strong> tarafında <strong>HTTPS</strong> tabanlı geliştirme ortamının hazırlanması daha önceki yıllarda biraz daha zorluydu. Ancak yeni nesil ortamlarımızda bu işlemleri gerçekleştirmek, adımlarımızda da görüldüğü üzere daha kolay. Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2012%2f10%2fHowTo_WCFandHTTPS.zip">HowTo_WCFandHTTPS.zip (63,74 kb)</a></p>2014-08-13T12:00:00+00:00bsenyurtDevelopment ortamında geliştirme yapmaktayız. IIS üzerinde host edilen bir WCF Servis uygulamamız var. Bu servis uygulaması WS Security standartlarında ve SSL tabanlı bir hizmet sunmakta. Bir başka deyişle servise https üzerinden talep gönderebiliyoruz. Servisin WSDL içeriğinin elde edilebildiği adres de aslında HTTPS tabanlı. İstemci tarafı ise Asp.Net tipinden bir web uygulaması. Bu uygulamanın söz konusu servise HTTPS tabanlı olarak talep gönderebilmesi ve cevap alabilmesi isteniyor. Development ortamında çalışıldığından gerçek bir sertifika yerine, Microsoft’ un test amaçlı X509 sertifikasının kullanılması planlanıyor.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=a5a9ce62-1f9c-4588-a73e-5cf78c4c0c312https://www.buraksenyurt.com/trackback.axd?id=a5a9ce62-1f9c-4588-a73e-5cf78c4c0c31https://www.buraksenyurt.com/post/AspNete28099-ten-HTTPS-Tabanlc4b1-WCF-Cagrc4b1sc4b1-Gerceklestirmek#commenthttps://www.buraksenyurt.com/syndication.axd?post=a5a9ce62-1f9c-4588-a73e-5cf78c4c0c31https://www.buraksenyurt.com/post/WCF-4-5-Task-Based-Asynchronous-OperasyonlarWCF 4.5–Task Based Asynchronous Operasyonlar2013-01-01T13:51:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/kronometrei.jpg"><img style="margin: 4px 0px; display: inline; float: right;" title="kronometrei" src="/pics/kronometrei_thumb.jpg" alt="kronometrei" width="240" height="193" align="right" /></a>Merhaba Arkadaşlar,</p>
<p>Yaklaşık olarak <strong>4 dakika 38 saniye</strong>…İzleyen yazıyı benim okuma hızım bu oldu. Aslında bu süre şu demek; Öğle arasına çıkmadan bir 4 dakika 38 saniye demek bu...Ya da geldikten sonra bir 4 dakika 38 saniye demek…Ya da sabah işe erken geldiğimizde ayırabileceğimiz bir 4 dakika 38 saniye demek...Ya da servisi/otobüsü/minibüsü beklerken ayırabileceğimiz 4 dakika 38 saniye demek. Hatta Facebook’ a, Twitter’ a, Linkedin’ e, Youtube’a bakmadan geçireceğimiz bir 4 dakika 38 saniye demek… E o halde ne duruyorsunuz?Ayırın işte o zamanı <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_165.png" alt="Winking smile" /></p>
<p>Bilindiği üzere <strong>.Net Framework 4.5</strong> ile birlikte altyapıya entegre olan <strong>async</strong> ve <strong>await</strong> anahtar kelimelerini kullanarak, <strong>task bazlı</strong> <strong>asenkron</strong> programlama teknikleri uygulanabilmektedir. Çok doğal olarak <strong>WCF 4.5</strong> tarafında da bunun bir yansımasını görmekteyiz. <strong>Visual Studio </strong>arabirimi üzerinden herhangibir <strong>WCF</strong> servis referansını istemci uygulamaya eklemeye çalıştığımızda <strong>Task</strong> bazlı operasyon desteği varsayılan olarak etkinleştirilmekte ve <strong>proxy</strong> tipi içeriğinde buna uygun metodlara yer verilmektedir. Dolayısıyla <strong>WCF<em>(Windows Communication Foundation)</em></strong> servislerini kullanan istemciler, operasyon çağrılarında <strong>async</strong> ve <strong>await</strong> anahtar kelimelerinden de yararlanabilirler.</p>
<p>Servislerin asenkron çağrılar ile yürütülmesi, özellikle <strong>User Experience</strong>’ ın önemli olduğu uygulamalarda, ön planda yer alan konular arasındadır. Gelin bu konuyu oldukça basit bir örnek üzerinden ele almaya çalışalım. İlk olarak <strong>.Net Framework</strong> <strong>4.5</strong> versiyonunda bir<strong> WCF Service Application</strong> oluşturup içerisine aşağıdaki sınıf diagramında<em>(Class Diagram)</em> görülen tipleri ilave edelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/tbawcf_1.png"><img style="margin: 4px 0px; display: inline;" title="tbawcf_1" src="/pics/tbawcf_1_thumb.png" alt="tbawcf_1" width="450" height="468" /></a></p>
<p><strong>OptimizationService</strong> sembolik olarak uzun süren bir optimizasyon işlemini üstelenecek şekilde planlanmıştır. Senaryo gereği istemciden bir lokasyon bilgisi almakta olan servis, bu lokasyon için en ideal yolu çıkartmaktadır. Sadece hayal ediyoruz tabi <img class="wlEmoticon wlEmoticon-openmouthedsmile" style="border-style: none;" src="/pics/wlEmoticon-openmouthedsmile_38.png" alt="Open-mouthed smile" /> Amacımız uzun süren bir işlem ile servis tarafının istemciye geç cevap dönmesini sağlamak ve asenkronluğu devreye almaktır.</p>
<p><strong>OptimizationService</strong> içerisinde yer alan <strong>GetBestRoot</strong> operasyonu <strong>Location</strong> tipinden bir parametre alırken, geriye de <strong>Root</strong> tipinden generic bir <strong>List</strong> koleksiyonu döndürmektedir. Servis uygulamasındaki tiplerin içerikleri ise aşağıdaki gibidir.</p>
<p><strong>Servis sözleşmesi(Service Contract);</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Collections.Generic;
using System.ServiceModel;
namespace AzonServiceApp
{
[ServiceContract]
public interface IOptimizationService
{
[OperationContract]
List<Root> GetBestRoot(Location yourLocation);
}
}</pre>
<p><strong>Servis sınıfı;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Collections.Generic;
using System.Threading;
namespace AzonServiceApp
{
public class OptimizationService
: IOptimizationService
{
public List<Root> GetBestRoot(Location yourLocation)
{
List<Root> roots=FindBestRoot(yourLocation);
return roots;
}
private List<Root> FindBestRoot(Location yourLocation)
{
Thread.Sleep(10000);
return new List<Root>{
new Root{RootId=1,Latitude=34.5,Longitude=43.2,Altitude=500.50,Title="4ncü cadde batı köşesi"},
new Root{RootId=2,Latitude=34.85,Longitude=43.2,Altitude=450,Title="moda sahil yolu"},
new Root{RootId=3,Latitude=22.5,Longitude=43.2,Altitude=100,Title="iskele caddesi durağı"},
new Root{RootId=4,Latitude=44.90,Longitude=12.90,Altitude=0,Title="iskelenin kendisi"}
};
}
}
}</pre>
<p><strong>Location tipi;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Runtime.Serialization;
namespace AzonServiceApp
{
[DataContract]
public class Location
{
[DataMember]
public int LocationId { get; set; }
[DataMember]
public string Title { get; set; }
}
}</pre>
<p><strong>Root tipi;</strong></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Runtime.Serialization;
namespace AzonServiceApp
{
[DataContract]
public class Root
{
[DataMember]
public double Altitude { get; set; }
[DataMember]
public double Longitude { get; set; }
[DataMember]
public double Latitude { get; set; }
[DataMember]
public int RootId { get; set; }
[DataMember]
public string Title { get; set; }
}
}</pre>
<p>Eğer servis uygulamasını bu haliyle çalıştırıp test edersek, <strong>WCF Test Client</strong> uygulamasında yaklaşık olarak <strong>10</strong> saniyelik bir gecikme ile <strong>Root</strong> listesini alabildiğimizi görürüz<em>(Nitekim <strong>GetBestRoot</strong> servis operasyonu içerisinde çağırılan <strong>FindBestRoot</strong> metodunda, <strong>Thread.Sleep</strong> ile <strong>10 saniyelik bir gecikme</strong> uygulanmıştır)</em></p>
<p><a href="https://www.buraksenyurt.com/pics/tbawcf_6.png"><img style="margin: 4px 0px; display: inline;" title="tbawcf_6" src="/pics/tbawcf_6_thumb.png" alt="tbawcf_6" width="598" height="500" /></a></p>
<p>Tabi asıl konumuz bizim geliştireceğimiz istemci uygulamalardaki task bazlı operasyon desteğidir. İstemci tarafını bir <strong>WPF Application</strong> olarak geliştirdiğimizi düşünebiliriz. Uygulamaya <strong>Add Service Reference</strong> seçeneği ile servisimizi eklemek istediğimizde, <strong>Advanced</strong> sekmesinden ulaşacağımız arabirimde yer alan <strong>Generate Task-Based Operations</strong> kutucuğunun varsayılan olarak işaretli olduğunu fark edebiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/tbawcf_2.png"><img style="margin: 4px 0px; display: inline;" title="tbawcf_2" src="/pics/tbawcf_2_thumb.png" alt="tbawcf_2" width="550" height="339" /></a></p>
<p>Bu duruma göre referansı eklediğimizde, istemci uygulama tarafında aşağıdaki sınıf diagramında yer alan tiplerin üretildiğini görürüz.</p>
<p><a href="https://www.buraksenyurt.com/pics/tbawcf_3.png"><img style="margin: 4px 0px; display: inline;" title="tbawcf_3" src="/pics/tbawcf_3_thumb.png" alt="tbawcf_3" width="543" height="554" /></a></p>
<p>Dikkat edileceği üzere <strong>OptimizationServiceClient</strong> sınıfı içerisinde, geriye <strong>Task<Root[]></strong> tipinden referans döndüren bir operasyon yer almaktadır; <strong>GetBestRootAsync</strong>. Bu dönüş tipi nedeniyle ilgili metod çağrısı <strong>awaitable’</strong> dır. Dolayısıyla <strong>async</strong> ile işaretlenmiş bir metod içerisindeyken <strong>await</strong> ile çağırılabilir. Dilerseniz bu durumu test etmeye çalışacak şekilde arayüzümüzü geliştirmeye devam edelim. Bu amaçla, <strong>WPF<em>(Windows Presentation Foundation)</em></strong> uygulamamızda yer alan <strong>MainWindow</strong> öğesinin <strong>XAML<em>(eXtensible Application Markup Language)</em></strong> içeriğini aşağıdaki gibi düzenleyelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/tbawcf_4.png"><img style="margin: 4px 0px; display: inline;" title="tbawcf_4" src="/pics/tbawcf_4_thumb.png" alt="tbawcf_4" width="477" height="264" /></a></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Window x:Class="WpfClientApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="250" Width="460">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<Button x:Name="btnGetRoot" Content="En iyi yol bilgisini getir"
HorizontalAlignment="Left" Margin="2,2,2,2" Click="btnGetRoot_Click_1"/>
<Label Content="Yana Birşeyler Yaz"/>
<TextBox Margin="3,3,3,3" Width="228"/>
</StackPanel>
<Label x:Name="lblStatus" Grid.Row="2" Content="Durum bilgisi"/>
<DataGrid x:Name="grdRoots" Grid.Row="1" ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=RootId}" Header=""/>
<DataGridTextColumn Binding="{Binding Path=Title}" Header="Yer"/>
<DataGridTextColumn Binding="{Binding Path=Longitude}" Header="Boylam"/>
<DataGridTextColumn Binding="{Binding Path=Latitude}" Header="Enlem"/>
<DataGridTextColumn Binding="{Binding Path=Altitude}" Header="Deniz Seviyesinden Yükseklik"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window></pre>
<p>Burada yer alan <strong>DataGrid</strong> kontrolünün içeriğini, servis üzerinden yapacağımız çağrı sonrası gelen <strong>Root[]</strong> referansı ile doldurmaya çalışıyor olacağız. Bu sebepten bir <strong>data</strong> <strong>bind</strong> işlemi uyguladık ve <strong>DataGrid</strong> kontrolünün kolonlarında da <strong>Root</strong> tipine ait özelliklere yer verdik<em>(RootId, Title, Longitude, Latitude ve Altitude)</em> Gelelim yazımızın can alıcı noktasına <img class="wlEmoticon wlEmoticon-sarcasticsmile" style="border-style: none;" src="/pics/wlEmoticon-sarcasticsmile_14.png" alt="Sarcastic smile" /> Kod içeriğini aşağıdaki gibi düzenleyelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Windows;
using WpfClientApp.AzonReference;
namespace WpfClientApp
{
public partial class MainWindow : Window
{
OptimizationServiceClient proxy = new OptimizationServiceClient();
public MainWindow()
{
InitializeComponent();
}
private async void btnGetRoot_Click_1(object sender, RoutedEventArgs e)
{
lblStatus.Content = "Bilgiler çekiliyor...";
Root[] roots = await proxy.GetBestRootAsync(
new Location {
LocationId = 1
, Title = "Hasanpaşa"
}
);
grdRoots.DataContext = roots;
lblStatus.Content = "Bilgiler çekildi...";
}
}
}</pre>
<p>İlk dikkat çekici nokta <strong>bntGetRoot_Click_1</strong> olay metodunun <strong>async</strong> anahtar kelimesi ile işaretlenmiş olmasıdır. Bu işaretleme nedeniyle, ilgili olay metodu içerisinde asenkron yürütülebilecek bir operasyon çağrısı yapılabileceği de belirtilmiş olmaktadır. Nitekim <strong>Root[]</strong> dizisinin çekilmesi için <strong>GetBestRootAsync</strong> metoduna yapılan çağrıda, <strong>await</strong> anahtar kelimesine yer verilmiştir. Olay metodu başında ve veriler <strong>DataGrid</strong> kontrolüne bağlandıktan sonra da <strong>lblStatus </strong>kontrolü içerisinde kısa bilgilendirmeler yapılmaktadır.</p>
<p>İşin güzel yanı ise şudur; Asenkron olarak çağırılan servis metodunun işleyişi sırasında, <strong>Form</strong>, kullanıcı tepkilerine cevap verebilir durumdadır. Yani ekran üzerinde formu başka bir yere sürükleyebilir, içeride yer alan <strong>TextBox</strong> kontrolünde bir şeyler yazabiliriz <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="/pics/wlEmoticon-winkingsmile_165.png" alt="Winking smile" /> </p>
<p>Oysaki eskiden, <strong>Dispatcher</strong>’ lardan ve hatta daha eskiden de <strong>Method Invoker</strong>’ lardan yararlanarak ekran arayüzünün cevap verebilir olmasını sağlamaya çalışırdık. Kafa karıştırıcı kodlar ile uğraşmak zorunda kalırdık. Bir kontrol için “hadi neyse…” derken, aynı anda yapılması gereken asenkron çağrı sayısının arttığı durumlarda kod kalabalığı ve karmaşıklığını daha da fazlalaştırıdık. Aslında uygulanan yeni model ile basitleşen bu durumu kendi gözlerinizle görmeniz daha iyi olacaktır. Ben sadece bir ekran görüntüsünü koyabilebileceğim. Siz mutlaka örnek kodu indirim test etmeye çalışın.</p>
<p><a href="https://www.buraksenyurt.com/pics/tbawcf_5.png"><img style="margin: 4px 0px; display: inline;" title="tbawcf_5" src="/pics/tbawcf_5_thumb.png" alt="tbawcf_5" width="460" height="250" /></a></p>
<p>Görüldüğü üzere <strong>async</strong> ve <strong>await</strong> anahtar kelimelerinden de yararlandığımız bu senaryoda, kod daha az karmaşık olmakla beraber, istemci arayüzünün de asenkron işleyiş sırasında cevap verebilir olması sağlanmıştır. <strong>WCF</strong> operasyonlarının <strong>Windows Phone 8</strong><em>(<a href="http://stackoverflow.com/questions/13173614/async-await-in-windows-phone-web-access-apis" target="_blank">Şu adresteki</a> tartışmaya da bir kulak verin)</em> gibi cevap verebilir arayüz ihtiyaçları yüksek olan uygulama çeşitlerinde de kullanıldığı düşünüldüğünde, kazanılan kabiliyetin önemli olduğu aşikardır. Böylece geldik kısa bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://www.buraksenyurt.com/pics/2012%2f12%2fHowTo_TaskBasedAsyncOperations.zip">HowTo_TaskBasedAsyncOperations.zip (167,69 kb)</a></p>2013-01-01T13:51:00+00:00wcftask parallel librarytask based asynchronousasyncawait.net 4.5.net framework 4.5windows communication foundationwcf 4.5bsenyurtBilindiği üzere .Net Framework 4.5 ile birlikte altyapıya entegre olan async ve await anahtar kelimelerini kullanarak, task bazlı asenkron programlama teknikleri uygulanabilmektedir. Çok doğal olarak WCF 4.5 tarafında da bunun bir yansımasını görmekteyiz. Visual Studio arabirimi üzerinden herhangibir WCF servis referansını istemci uygulamaya eklemeye çalıştığımızda Task bazlı operasyon desteği varsayılan olarak etkinleştirilmekte ve proxy tipi içeriğinde buna uygun metodlara yer verilmektedir. Dolayısıyla WCF(Windows Communication Foundation) servislerini kullanan istemciler, operasyon çağrılarında async ve await anahtar kelimelerinden de yararlanabilirler.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=9993af51-ed7f-4ef4-a9c2-69fec026f81a3https://www.buraksenyurt.com/trackback.axd?id=9993af51-ed7f-4ef4-a9c2-69fec026f81ahttps://www.buraksenyurt.com/post/WCF-4-5-Task-Based-Asynchronous-Operasyonlar#commenthttps://www.buraksenyurt.com/syndication.axd?post=9993af51-ed7f-4ef4-a9c2-69fec026f81a