https://www.buraksenyurt.com/
Burak Selim Şenyurt - bing
2016-08-03T13:09:13+00:00
Matematik Mühendisi Bir Bilgisayar Programcısının Notları
Burak Selim Senyurt
BlogEngine.Net Syndication Generator
https://www.buraksenyurt.com/opml.axd
Burak Selim Senyurt
Matematik Mühendisi Bir Bilgisayar Programcısının Notları
tr-TR
Burak Selim Şenyurt
0.000000
0.000000
https://www.buraksenyurt.com/post/BING-Maps-WCF-Rest-Servislerini-Kullanmak
BING Maps WCF Rest Servislerini Kullanmak
2012-04-02T04:00:00+00:00
bsenyurt
<p><a href="https://www.buraksenyurt.com/pics/Garfield-1.jpg"><img style="display: inline; margin-left: 0px; margin-right: 0px;" title="Garfield-1" src="/pics/Garfield-1_thumb.jpg" alt="Garfield-1" width="280" height="210" align="right" /></a>Merhaba Arkadaşlar,</p>
<p>Bazen öğrenmek istediklerimiz bize inanılmaz karşık gelir. Ne zaman kitabı açsak ya da bilgisayarın başına geçsek işe zaten demoralize olmuş bir şekilde başlarız. Özellikle tez hazırlıkları safhasındayken veya yazacağımız kitap için gerekli araştırmaları yaparken çok yoğun, ağır, sıkıcı ve uğraştırıcı unsurlarla karşı karşıya kalabiliriz.</p>
<p>Yüksek Lisans yaptığım dönemlerdeki hocalarımdan birisi bu konuda şöyle bir tavsiye de bulunmuştu…</p>
<blockquote>
<p>Araştırmanızda bir nokta da tıkandınız, takıldınız mı?(Bir süre sessizlik)…Tatile çıkın. Bir iki hafta o konu ile hiç uğraşmayın. Döndüğünüzde soruna çok daha farklı bir şekilde bakacağınızı göreceksiniz <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
</blockquote>
<p>Doğruyu söylemek gerekirse hangi yolu kullanırsak kullanalım, kendimizi nasıl motive etmek istersek isteyelim, bazen araştırdığımız konu da öyle bir nokta yakalarız ki, gerisi çorap söküğü gibi gelir. İşte bu yazımızda bu çorap söküğünü bulmaya çalışıyor olacağız.</p>
<p>Hatırlayacağınız üzere <strong>BING Maps WCF Servislerini</strong> değerlendirdiğimiz <a href="https://www.buraksenyurt.com/post/Bing-Maps-WCF-Servisleri" target="_blank">bir önceki yazımızda</a>, söz konusu hizmetlerden yararlanabilmek için <strong>proxy</strong> tiplerinden faydalanmıştık<em>(Add Service Reference)</em>. Ancak bu servisleri sadece <strong>proxy</strong> tipleri üzerinden kullanmak gibi bir zorunluluğumuz bulunmamaktadır. Özellikle son yıllarda ön plana çıkan <strong>REST</strong> tabanlı servis yaklaşımı sayesinde, ilgili hizmetlerden <strong>HTTP</strong> protokolünün <strong>GET</strong> metodunu kullanaraktan da yararlanabiliriz. Bu çok doğal olarak platform bağımsızlık avantajını da beraberinde getirecektir. İşte bu yazımızda <strong>BING</strong> <strong>Maps</strong> servislerine ait <strong>REST(Representational State Transfer) </strong>arayüz noktalarını nasıl kullanabileceğimizi çok basit bir örnek üzerinden incelemeye çalışıyor olacağız. Gerisi çorağ söküğü gibi gelecek</p>
<p><strong>BING Maps Rest</strong> servisleri de toplamda dört arayüz ile karşımıza çıkmaktadır. Adres, nokta bazlı yer bulma işlemleri vb için <strong>Locations API</strong>, harita bazlı rota gösterme ve metadata bilgisi elde edebilmek vb için <strong>Imagery API</strong>, yürüme yolu, araç yolu veya transit geliş gidişlere yönelik rota çıkartılması vb için <strong>Routes API</strong>, coğrafi bir alandaki trafik durum bilgisini vb öğrenebilmek için de <strong>Traffic API</strong> <strong>REST</strong> servislerinden yararlanılabilmektedir.</p>
<p>Aslında tüm <strong>API</strong> arayüzleri <strong>HTTP</strong> protokolünün <strong>GET</strong> metoduna göre talep kabul etmekte ve istemci tarafına buna uygun olacak şekilde <strong>XML(eXtensible Markup Language)</strong>veya <strong>JSON(JavaScript and Object Notation)</strong> çıktısı döndürmektedir. Bu iki çıktı içeriği de <strong>W3C</strong> tarafından kabul görmüş birer standart olduğundan, herhangibir platform tarafından kolaylıkla kullanılabilir. Hatta en basit anlamda tarayıcı uygulamalar tarafından kolayca gösterilebilir. Dolayısıyla bilinmesi gereken, bu <strong>API</strong> arayüzlerine gönderilecek olan <strong>URL</strong> formatının nasıl olması gerektiği ve çıktıların kod tarafında nasıl ele alınabileceğidir.</p>
<p>İşe ilk olarak basit bir adım ile başlarsak gerisi çorap söküğü gibi gelecektir. Bu amaçla öncelikle bir adres bazlı lokasyon konumlandırma işinden başlayalım derim. Örneğin herhangibir tarayıcı üzerinden aşağıdaki talepte bulunduğumuzu düşünelim.</p>
<p><strong>http://dev.virtualearth.net/REST/v1/Locations/US/NH/manchester/?o=xml&key={Buraya Developer API Key gelmeli}</strong></p>
<p>Bu <strong>URL</strong> ifadesinden <strong>Locations REST </strong>arayüzüne<em>(ve hatta 1.0 versiyonuna)</em> bir talepte bulunduğu görülmektedir. <strong>US</strong> ile başlayan kısımda tahmin edileceği üzere ülke kodu belirtilir. Bu örnekte <strong>Amerika Birleşik Devleteri(United States) </strong>seçilmiştir. <strong>US</strong> kodunu izleyen kısımda ise bölge adının yazıldığı görülmektedir, <strong>NH</strong>. Sonraki kısımda ise şehir adı gelmektedir ki bu örnekte <strong>Manchester</strong> aranmaktadır. <strong>?o</strong> ile başlayan bölümde ise çıktı formatının tipi seçilir ki burada <strong>XML</strong> biçimi ele alınmıştır. Çok doğal <strong>BING Maps</strong> hizmetlerinden yararlanabilmek için bir <strong>Developer Key</strong> olması gerekmektedir. <strong>key</strong> anahtar kelimesinden sonra gelen kısımda da bu değer yazılır. Ben kendi developer key değişkenimi kullandığımda aşağıdaki <strong>XML</strong> çıktısını elde ettiğimi gördüm.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><Response>
<Copyright>
Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.
</Copyright>
<BrandLogoUri>
http://dev.virtualearth.net/Branding/logo_powered_by.png
</BrandLogoUri>
<StatusCode>200</StatusCode>
<StatusDescription>OK</StatusDescription>
<AuthenticationResultCode>ValidCredentials</AuthenticationResultCode>
<TraceId>
3c54bda6227b45a58f6c9947a79021d8|LTSM001153|02.00.83.500|LTSMSNVM002004, LTSMSNVM001455, LTSMSNVM001474, LTSMSNVM001465, LTSMSNVM001451, LTSMSNVM002052
</TraceId>
<ResourceSets>
<ResourceSet>
<EstimatedTotal>1</EstimatedTotal>
<Resources>
<Location>
<Name>Manchester, NH</Name>
<Point>
<Latitude>42.991168975830078</Latitude>
<Longitude>-71.463088989257812</Longitude>
</Point>
<BoundingBox>
<SouthLatitude>42.936458587646484</SouthLatitude>
<WestLongitude>-71.510566711425781</WestLongitude>
<NorthLatitude>43.043960571289062</NorthLatitude>
<EastLongitude>-71.415084838867188</EastLongitude>
</BoundingBox>
<EntityType>PopulatedPlace</EntityType>
<Address>
<AdminDistrict>NH</AdminDistrict>
<AdminDistrict2>Hillsborough Co.</AdminDistrict2>
<CountryRegion>United States</CountryRegion>
<FormattedAddress>Manchester, NH</FormattedAddress>
<Locality>Manchester</Locality>
</Address>
<Confidence>Medium</Confidence>
<MatchCode>Good</MatchCode>
<MatchCode>UpHierarchy</MatchCode>
<GeocodePoint>
<Latitude>42.991168975830078</Latitude>
<Longitude>-71.463088989257812</Longitude>
<CalculationMethod>Rooftop</CalculationMethod>
<UsageType>Display</UsageType>
</GeocodePoint>
</Location>
</Resources>
</ResourceSet>
</ResourceSets>
</Response></pre>
<p>Görüldüğü üzere söz konusu çıktı içerisinde Manchester mevkisinin coğrafik lokasyon bilgileri yer almaktadır. İlgili <strong>XML</strong> içeriğinin şemasını çıkarttığımızda ağaç yapısını daha kolay bir şekilde görebiliriz ve anlayabiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/bngrest1.png"><img style="display: inline;" title="bngrest1" src="/pics/bngrest1_thumb.png" alt="bngrest1" width="286" height="547" /></a> </p>
<p>Aslında lokasyon ile ilişkili olarak asıl önemli bilgiler <strong>Resources/Location</strong> elementi altındaki boğumlarda yer almaktadır. Söz gelimi <strong>Name</strong> elementinde aranan kritere uygun olarak gelen lokasyonun adı, <strong>BoundingBox</strong> içerisinde kuzey, güney, doğu ve batı koordinatları, <strong>Point</strong> elementinde enlem ve boylam bilgileri vb yer almaktadır. Aranan içeriğin eşleşme oranı ise<em>(yani bulunan sonucun aranan ile ne kadar yakın olduğu bilgisi de)</em> <strong>MatchCode</strong> elementi içerisinde belirtilmektedir.</p>
<p>Aranan kritere göre çok daha fazla sonuç gelmesi de olasıdır. Örneğin,</p>
<p><strong>http://dev.virtualearth.net/REST/v1/Locations/manchester/?o=xml&key={developer key}</strong></p>
<p>şeklinde bir <strong>URL</strong> talebinde bulunduğumuzda bize an itibariyle 5 adet sonuç dönecektir. Nitekim burada ülke veya lokasyonu tam onikiden vurmak için gerekli ekstra bilgiler verilmemiştir. Sadece <strong>BING</strong> serverlarında kayıtlı olan <strong>manchester</strong> mevkisine ait veriler getirilmiş ve makalenin yazıldığı tarih itibariyle de 5 yakın sonuç bulunmuştur. <em>(Örnek erkan görüntüsünün bir kısmı aşağıdaki gibidir)</em></p>
<p><a href="https://www.buraksenyurt.com/pics/bngrest4.png"><img style="display: inline;" title="bngrest4" src="/pics/bngrest4_thumb.png" alt="bngrest4" width="355" height="678" /></a></p>
<p>Bir kaç farklı örnek daha ilave ederek <strong>REST</strong> arayüz içeriklerini incelemeye devam edelim.</p>
<p><strong>http://dev.virtualearth.net/REST/v1/Locations/turkey/kadiköy/?output=xml&key={Developer key}</strong></p>
<p>Yukarıdaki sorgu ile Türkiye’ deki Kadıköy ilçesinin lokasyon bilgisi elde edilebilir.</p>
<p><a href="https://www.buraksenyurt.com/pics/bngrest3.png"><img style="display: inline;" title="bngrest3" src="/pics/bngrest3_thumb.png" alt="bngrest3" width="426" height="588" /></a></p>
<p><strong>http://dev.virtualearth.net/REST/v1/Locations?output=xml&countryRegion=DE&key={Developer Key}</strong></p>
<p>Bu seferki sorgu ile de countryRegion=DE anahtar değer çiftini kullanarak Almanya’ nın merkez koordinatlarını elde edebiliriz.</p>
<p>Peki çıktıyı <strong>JSON</strong> formatında almak istersek? Bu durumda <strong>URL</strong> sorgusundaki ufak bir değişiklik yapmamız yeterli olacaktır. Özellike <strong>WCF Data Service</strong> geliştiricileri, <strong>URL</strong>içerisinde önceden tanımlı pek çok anahtar kelimenin kullanıldığını bilirler. <strong>BING Maps REST</strong> servislerinde de benzer bir durum söz konusudur. Nitekim <strong>?</strong> den sonra gelen kısımlarda <strong>anahtar kelime=değer</strong> şeklinde <strong>key-value</strong> çiftleri yer almaktadır. Bu çiftlerlerin sayısı & operatörü ile arttırılabilir ve birden fazla kriterin hesaba katılması sağlanabilir. Eğer <strong>o</strong> parametresinin değeri <strong>xml’</strong> den <strong>json’</strong> a çekilirse, bu karşı taraftaki <strong>BING Map Locations REST</strong> servisi için çıktının <strong>JSON</strong> formatında hazırlanması gerektiği anlamına gelecektir.</p>
<p><strong>http://dev.virtualearth.net/REST/v1/Locations/us/nh/manchester/?o=json&key={developer key}</strong></p>
<p>Bu <strong>URL</strong> talebinin sonucunda aşağıdaki içerikte görülen <strong>JSON</strong> formatlı çıktı elde edilmiştir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false">{"authenticationResultCode":"ValidCredentials","brandLogoUri": "http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png","copyright":"Copyright © 2012 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.","resourceSets":
[
{"estimatedTotal":1,"resources":
[
{"__type": "Location:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1","bbox":
[42.936458587646484, -71.510566711425781,43.043960571289062, -71.415084838867188],"name":"Manchester, NH","point":
{"type":"Point","coordinates":[42.991168975830078,-71.463088989257812]},"address":
{"adminDistrict":"NH","adminDistrict2":"Hillsborough Co.", "countryRegion":"United States","formattedAddress":"Manchester, NH","locality":"Manchester"},"confidence":"High","entityType":"PopulatedPlace","geocodePoints":
[{"type":"Point","coordinates":[42.991168975830078,-71.463088989257812] ,"calculationMethod":"Rooftop","usageTypes":["Display"]}],"matchCodes":["Good"]
}
]}
],"statusCode":200,"statusDescription":"OK","traceId":"d9816448d7e340c0a457ba230bd56310| LTSM001158|02.00.83.500|LTSMSNVM001472, LTSMSNVM002206, LTSMSNVM001475, LTSMSNVM001455, LTSMSNVM001465"
}</pre>
<p>Pek tabi <strong>JSON</strong> formatlı çıktılar, <strong>XML</strong> formatlı çıktılara nazaran çok daha az yer kaplamaktadır.</p>
<p>Diğer servislerinde <strong>REST</strong> arayüzlerini kullanmak suretiyle çeşitli aramalar yapabiliriz. Örneğin <strong>Routes</strong> <strong>API</strong> arayüzüne kısa bir bakış atalım. Bu arayüzü kullanarak yürüyüş, sürüş veya transit geliş gidişler için rota bilgisi elde etmemiz mümkündür. Eğer <strong>İstanbul’ </strong>dan <strong>Ankara’</strong> ya doğru araba ile gideceğimiz bir rota bilgisi istersek, aşağıdaki gibi bir URL sorgusunu göndermemiz yeterli olacaktır.</p>
<p><strong>http://dev.virtualearth.net/REST/V1/Routes/Driving?o=xml&wp.0=istanbul&wp.1=ankara&avoid=minimizeTolls&distanceUnit=km&key={Developer Key}</strong></p>
<p>Sorgu sonucu elde edilen uzun XML çıktısına ait küçük bir ekran görüntüsü</p>
<p><a href="https://www.buraksenyurt.com/pics/bngrest2.png"><img style="display: inline;" title="bngrest2" src="/pics/bngrest2_thumb.png" alt="bngrest2" width="611" height="750" /></a></p>
<p>Bu <strong>URL</strong> sorgusunda önemli olan bazı <strong>key’</strong> ler vardır. <strong>wp.0</strong> ve<strong> wp.1</strong> ile tanımlanan anahtar kelimelere atanan değerler, sırasıyla <strong>WayPoint 1</strong> ve <strong>WayPoint 2</strong> anlamına gelmektedir. Bir başka deyişle, rota için gerekli <strong>başlangıç</strong> ve <strong>bitiş noktaları</strong> bilgileridir. <strong>avoid</strong> kelimesi seçimliktir ve burada atanan <strong>minimizeTolls</strong> değeri ile paralı yolların mümkün mertebe rota tanımından çıkartılması talep edilmektedir. <strong>distanceUnit=km</strong> anahtar değer çifti ile mesafelerin <strong>km</strong> cinsinden bildirilmesi sağlanmaktadır ki diğer seçenekte <strong>mil</strong> anlamına gelen <strong>mi’</strong> dir.</p>
<blockquote>
<p>Diğer kullanılabilecek key değerleri için <a href="http://msdn.microsoft.com/en-us/library/ff701717.aspx" target="_blank">developer sayfasına</a> bir göz atmanızı öneririm. Oldukça fazla sayıda alternatif bulunmaktadır.</p>
</blockquote>
<p>Diğer API arayüzlerinden olan Static MAP Rest arayüzü ile de standart olarak 350X350 boyutlarında harita elde edilmesi mümkün olmaktadır. Bu haritayı uydu görüntüsü şeklinde, yol haritası şeklinde elde etmemiz de söz konusudur. Aslına bakarsanız BING Maps hizmetlerinin bana kalırsa en eğlencelilerinden birisi de bu API’ dir. Örneğin</p>
<p><strong>http://dev.virtualearth.net/REST/v1/Imagery/Map/AerialWithLabels/istanbul?mapSize=400,300&key={developer key}</strong></p>
<p>URL sorgusu sonucunda aşağıdaki çıktıyı elde ederiz.</p>
<p><a href="https://www.buraksenyurt.com/pics/bngrest5.png"><img style="display: inline;" title="bngrest5" src="/pics/bngrest5_thumb.png" alt="bngrest5" width="412" height="313" /></a></p>
<p>Bu sorguda <strong>Imagery/Map/AerialWithLabels</strong> ile şehrin coğrafik haritasının başlık bilgileri kullanılarak gösterileceği belirtilmektedir. istanbul kelimesini takip eden kısımlarda ise <strong>mapSize</strong> anahtar kelimesi kullanılmış ve üretilecek olan haritanın <strong>400,300</strong> boyutlarında olması sağlanmıştır.</p>
<p><strong>http://dev.virtualearth.net/REST/v1/Imagery/Map/Road/Routes?wp.0=istanbul&wp.1=kocaeli&format=png&mapSize=800,600&key={developer key}</strong></p>
<p>Yukarıdaki sorguda ise, yol haritası istenmektedir. <strong>Map/Road</strong> adresine gidilmesinin sebebi budur. Diğer taraftan <strong>Routes</strong> anahtar kelimesine atanan iki <strong>Way Point </strong>değeri ile <strong>İstanbul</strong> ile <strong>Kocaeli</strong> arası yol haritasının gösterilmesi talep edilmiştir. Söz konusu harita <strong>800X600</strong> pixel boyutlarında olacaktır ve <strong>png</strong> formatında üretilecektir. İşte sonuç,</p>
<p><a href="https://www.buraksenyurt.com/pics/bngrest6.png"><img style="display: inline;" title="bngrest6" src="/pics/bngrest6_thumb.png" alt="bngrest6" width="640" height="488" /></a></p>
<p><strong>Imagery</strong> servisindeki diğer anahtar kelimeler için yine <strong>BING</strong> <strong>developer</strong> <strong>center’</strong> daki <a href="http://msdn.microsoft.com/en-us/library/ff701724.aspx" target="_blank">web sayfasını</a> ziyaret etmenizi öneririm.</p>
<p>Buraya kadar kı kısımda, söz konusu <strong>REST</strong> tabanlı servislerin <strong>HTTP GET</strong> talepleri ile nasıl sorgulanabileceğini anlamaya çalıştık. Görüldüğü gibi sorgu cümlesi içerisinde kullanılabilecek çok fazla sayıda <strong>key=value</strong> çifti bulunmaktadır. Sorguların sonuçlarını <strong>XML</strong> veya <strong>JSON</strong> formatında alabiliyor olmamız tüm platformların desteklenmesi açısından da oldukça önemlidir. Tabi <strong>Imagery</strong> servisi kullandığımızda çıktılar <strong>GIF, JPG</strong> veya <strong>PNG</strong> formatında olmaktadır.</p>
<p>Ancak çıktılar hangi format olurlarsa olsunlar, sonuç itibariyle bu üretimin kod tarafında anlamlı ve işe yarar hale getirilmesi gerektiğinden eminim ki hepimiz hem fikirizdir. Öyleyse dilerseniz basit bir kod parçası yardımıyla, <strong>Locations REST</strong> arayüzüne nasıl talepte bulunabileceğimize ve sonuçları nasıl değerlendirebileceğimize bakalım. Bu amaçla aşağıdaki kod parças ile işe başlayalım.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Xml.Linq;
namespace BingRestClient
{
class Program
{
static void Main(string[] args)
{
// BING Maps servisleri için kullanacağımız Developer Key değerini config dosyasından okuyoruz
string apiDeveloperKey = ConfigurationManager.AppSettings["DeveloperKey"].ToString();
// Basit bir sorgu giriyoruz. Birden fazla Location' ı ele almak istediğimizden sadece manchester değerini verdik
string query = "manchester";
// Tüm elemenler xmlNamespace değişkeni ile tanımlı Xml Namespace' i kullanmakta
string xmlNamespace = "http://schemas.microsoft.com/search/local/ws/rest/v1";
// Buna bağlı olarak gerekli XmlNamespace tanımlamalarını içeren XName değişkenleri oluşturuluyor. Bunlar XLINQ sorgusunda kullanılıyor olacak.
XName resourceSetsName = XName.Get("ResourceSets", xmlNamespace);
XName resourceSetName = XName.Get("ResourceSet", xmlNamespace);
XName resourcesName = XName.Get("Resources", xmlNamespace);
XName locationName = XName.Get("Location", xmlNamespace);
XName name = XName.Get("Name", xmlNamespace);
XName point = XName.Get("Point", xmlNamespace);
// HTTP GET ile gidecek olan sorgu oluşturuluyor
string url = String.Format("http://dev.virtualearth.net/REST/v1/Locations/{0}/?o=xml&key={1}", query, apiDeveloperKey);
XElement locationElement = null;
try
{
// XElement tipinin static Load metodu yardımıyla ilgili URL' e talepte bulunuluyor.
locationElement = XElement.Load(url);
// Basit bir XLINQ sorgusu kullanılarak ResourceSet elementlerine kadar iniliyor
var resourceSet = from n in locationElement
.Elements(resourceSetsName)
.Elements(resourceSetName)
.Elements(resourcesName)
.Elements(locationName)
select n;
foreach (var r in resourceSet) //Her bir ResourceSet elementi dolaşılıyor
{
Console.WriteLine(r.Element(name).Value); // önce Name elementinin değeri
foreach (var p in r.Elements(point)) // ardından her bir Point elementi içerisindeki her bir elementin değeri (ki bunlar longtitude ve latitude değerleri) dolaşılıp ekrana yazdırılıyor.
{
Console.WriteLine("\t{0}\t", p.Value);
}
}
}
catch (WebException excp)
{
Console.WriteLine(excp.Message);
}
}
}
}</pre>
<p>Kodda dikkat edilmesi gereken noktalardan bir tanesi, <strong>XLINQ </strong>sorgularını gönderirken <strong>XmlNamespace </strong>kullanılmasıdır. Eğer bu <strong>Xml Namespace</strong> bilgisini ele almazsak söz konusu elementlerin hiç birisine ulaşamayız. Diğer yandan, <strong>URL </strong>bazlı olarak okuma işlemini gerçekleştirmek için, <strong>XElement </strong>tipinin <strong>static Load </strong>metodundan yararlanılmıştır. Eğer URL geçerli ise dönen sonuç <strong>XML </strong>formatında, <strong>XElement </strong>nesne örneğine yüklenecektir. Biz de bu içerik üzerinde dolaşarak sadece lokasyonun adını ve enlem ile boylam değerlerini ekrana yazdırmaya çalıştık. Örneğimizi çalıştırdığımızda aşağıdaki ekran görüntüsü ile karşılaşırız.</p>
<p><img style="border-style: initial; border-color: initial;" src="/pics/2012%2f2%2fbingrest10.png" alt="" /></p>
<p>Görüldüğü üzere <strong>manchester </strong>kelimesi için <strong>BING </strong>servisi dünya üzerinde 5 adet lokasyon bilgisi önermiştir. Çok doğal olarak örneğimiz <strong>XML </strong>formatını değerlendirecek şekilde geliştirilmiştir. Eğer <strong>JSON </strong>formatında bir içerik okumak istersek bu durumda JSON ile ilişkili serileştirme tipinden<strong>(DataContractJsonSerializer)</strong> yararlanabiliriz. <em>(Bu konuda MSDN üzerinden yayınlanan <a href="http://msdn.microsoft.com/en-us/library/hh674188.aspx" target="_blank">şu makaleyi </a>incelemenizi öneririm.)</em></p>
<p>Yazımızı sonlandırmadan önce son olarak Imagery servisine ait basit bir kod parçası geliştirelim. <strong>Imagery </strong>servisi bildiğiniz üzere <strong>XML </strong>veya <strong>JSON </strong>formatı yerine, <strong>JPEG, PNG</strong> veya <strong>GIF </strong>formatında resim çıktısı sunabilmektedir. Dolayısıyla bu servise yapacağımız talepleri farklı bir şekilde ele almamız gerekmektedir. İşte örnek kod parçamız.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">string imagerUrl = String.Format("http://dev.virtualearth.net/REST/v1/Imagery/Map/Road/Routes?wp.0=istanbul&wp.1= kocaeli&format=png&mapSize=800,600&key={0}", apiDeveloperKey);
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(imagerUrl);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
List<byte> content = new List<byte>();
using (Stream stream = response.GetResponseStream())
{
int currentByte;
while ((currentByte = stream.ReadByte()) != -1)
{
content.Add((byte)currentByte);
}
}
string filePath = String.Format("{0}.png", Path.Combine(Environment.CurrentDirectory, Guid.NewGuid().ToString()));
File.WriteAllBytes(filePath, content.ToArray());
}
}
catch (WebException excp)
{
Console.WriteLine(excp.Message);
}</pre>
<p>Bu sefer bir <strong>Stream </strong>kullanmak durumundayız. Nitekim <strong>URL </strong>olarak talep ettiğimiz sorgu sonucunda bize okunabilir bir grafik içeriği gelmekte. Talebi oluşturmak ve<strong>response </strong>içeriğini almak için <strong>HttpWebRequest </strong>ve <strong>HttpWebResponse </strong>tiplerinden yararlandık. <strong>HttpWebResponse </strong>ile elde ettiğimiz nesne örneği üzerinden hareket ederek bir <strong>Stream </strong>oluşturduk ve bu <strong>Stream </strong>nesne örneği üzerinden resim dosyasına ait her bir <strong>byte </strong>içeriğini okuyarak generic bir <strong>List<byte> </strong>koleksiyonunda topladık. Çok doğal olarak elde edilen<strong> byte[]</strong> içeriği resim dosyasının kendisini ifade etmektedir. Bunu da sembolik olarak üretilen ve <strong>GUID </strong>ile isimlendirdiğimiz örnek bir dosyaya <strong>File </strong>tipinin<strong>static</strong> <strong>WriteAllBytes </strong>metodu ile kaydettik. İşte sonuç;</p>
<p><img style="border-style: initial; border-color: initial;" src="/pics/2012%2f2%2fbingrest11.png" alt="" /></p>
<p>Artık çorabı yırttık diye düşünüyorum. Bir başka deyişle gerisinin çorap söküğü gibi gelmesi lazım. Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim <img style="border-style: initial; border-color: initial;" title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<p><a href="https://www.buraksenyurt.com/pics/2012%2f2%2fBingRestClient.rar">BingRestClient.rar (1,20 mb)</a></p>
2012-04-02T04:00:00+00:00
bing maps
wcf rest
wcf
bsenyurt
Hatırlayacağınız üzere BING Maps WCF Servislerini değerlendirdiğimiz bir önceki yazımızda, söz konusu hizmetlerden yararlanabilmek için proxy tiplerinden faydalanmıştık(Add Service Reference). Ancak bu servisleri sadece proxy tipleri üzerinden kullanmak gibi bir zorunluluğumuz bulunmamaktadır.
https://www.buraksenyurt.com/pingback.axd
https://www.buraksenyurt.com/post.aspx?id=badca026-b584-4002-8f41-4cbd77a0cc7c
0
https://www.buraksenyurt.com/trackback.axd?id=badca026-b584-4002-8f41-4cbd77a0cc7c
https://www.buraksenyurt.com/post/BING-Maps-WCF-Rest-Servislerini-Kullanmak#comment
https://www.buraksenyurt.com/syndication.axd?post=badca026-b584-4002-8f41-4cbd77a0cc7c
https://www.buraksenyurt.com/post/Merhaba-Bing-API-20
Merhaba Bing API 2.0
2009-08-25T11:15:00+00:00
bsenyurt
<p><img style="float: right;" src="/pics/2009%2f8%2fblg72_Giris.gif" alt="" />Merhaba Arkadaşlar,</p>
<p>Bir süredir <strong>WCF 4.0</strong> ile birlikte gelen yenilikleri sizlere aktarmaya çalışıyorum. Son olarak <strong>Routing Service</strong> ile ilişkili bir giriş yazımız olmuştu. Bu konu ile ilişkili örnek en kısa sürede sizlerle olacak. Ne varki konu biraz zorlu. <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Bu yüzden bende yüksek lisans eğitimi aldığım yıllarda çok sevgili hocam <strong>Halil Seyidoğlu'</strong> nun bir açıklamasını uygulamaya karar verdim.</p>
<p>Kendisi bize <strong>"Bilimsel Araştırma ve Yazma"</strong> dersinde şöyle seslenmişt; <strong>"Bir tez konusunu araştırırken çok zorlu yollardan geçersiniz. Tezin bir noktasında tıkandınız mı? O zaman ara verin...Tatile çıkın...Bir süreliğine uzaklaşın..."</strong></p>
<p>Her ne kadar <strong>WCF 4.0</strong> ile gelen yenilikleri araştırmak bir tez hazırlamak kadar zorlu ve çetin olmasada sıkıldığım noktada hemen bir kaçış aradım ve bakım ne buldum.</p>
<p><strong>Bing API 2.0</strong></p>
<p><strong>Microsoft'</strong> un arama motoru <strong>Bing'</strong> i duymayan olmamıştır sanırım. Peki <strong>Bing'</strong> in kendi uygulamalarımızda kullanılabilmesi için dışarıya bir <strong>API</strong> sunduğunu biliyor muydunuz? Ta ta ta taaaa...<img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /> İşin içerisinde bir developer API'si, helede servis bazlı bir sunum olunca, değmeyin keyfime dedim ve yola koyuldum. Dolayısıyla bu yazımda sizlere Bing API' si ile ilişkili ilk izlenimlerimi ve çıkarımlarımı aktarmaya çalışacağım.</p>
<p><strong>Bing API'</strong> si, kendi web sitesinden sunduğu arama özelliklerinin tamamını, farklı iletişim protokollerine göre istemci tarafına servis bazlı olarak sunmaktadır. Buna göre dilersek <strong>Bing</strong> üzerinden gerçekleştirilen arama kabiliyetlerini ve sonuçlarını, kendi uygulamalarımıza entegre ederek kullanabiliriz. <strong>Bing</strong> hizmetinden yararlanabilmek için öncelikli olarak <a href="http://www.bing.com/developers/">http://www.bing.com/developers/</a> adresindeki formu doldurmamız ve yeni bir <strong>App Id</strong> almamız gerekmektedir. Nitekim Live servisi ile olan haberleşmede <strong>App Id</strong> değerinden yararlanılmaktadır. Teori oldukça basittir. Arama kutucuğundan yapılan kabliyetleri, kendi uygulamamızdan bir şekilde request olarak göndermemiz gerekmektedir. Bu noktada aslında, <strong>Bing API</strong> ile neler yapabileceğimiz kararının nasıl verildiğine bakmamızda yarar vardır. Söz konusu karar verilirken aslında aramanın tipini/modelinide belirlemiş oluruz. Yada var olan aramayı genişletmiş oluruz. İşte burada a bahsedilen arama modelleri belirlenirken <strong>SourceTypes</strong> isimli tip değerlerinden yararlanılmaktadır. <strong>SourceTypes'</strong> ın değerleri <strong>managed code</strong> tarafında verilebileceği gibi, örneğin <strong>HTTP Get</strong> metoduna bağlı olarak <strong>URL</strong> formatında da yazılabilir. Genel <strong>SourceTypes</strong> değerleri ve uygulayabileceğimiz arama modelleri aşağıdaki gibidir;</p>
<ul>
<li>Web sayfaları,</li>
<li>Resimler(Image),</li>
<li>Videolar(Video),</li>
<li>Dil çevirileri,</li>
<li>Lokasyonlar,</li>
<li>Uygulamanız ile alakalı reklamlar. Güncel SDK dökümanına göre sadece US sınırlarında geçerli.(Ads),</li>
<li>MSN Encarta Online Encyclopedia' den anlık cevaplar. Örneğin What is 100*37? sonucunun bulunması(Instant Answer),</li>
<li>XHTML veya WML formatında Mobile cihazlar için daha az yer harcayan sonuçlar(MobileWeb),</li>
<li>Güncel arama ile ilişkili olan aramalar(Related Search),</li>
<li>Haber içeriklerinin aranabilmesi(News),</li>
<li>Hava durumu ile ilişkili aramalar(Weather)</li>
<li>vb...</li>
</ul>
<p>Güzel. Şimdi kafamızda bir şeyler şekillenmeye başladı. En azından arama modelini nasıl seçebileceğimizi anladık. Peki talepler nasıl iletilecekler? <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> İstemciler taleplerini <strong>Bing API</strong> servisine 3 farklı formatta iletebilirler.</p>
<table style="width: 100%;" border="1" cellspacing="0" cellpadding="5">
<tbody>
<tr>
<td style="width: 10%;" valign="top"><strong>Format</strong></td>
<td style="width: 40%;" valign="top"><strong>Özet</strong></td>
<td style="width: 50%;" valign="top"><strong>URL</strong></td>
</tr>
<tr>
<td valign="top"><strong>JavaScript Object Notation(JSON)</strong></td>
<td valign="top"><strong>Ajax</strong> tabanlı uygulamalarda kullanılması tercih edilen bu tipe göre istemciye<strong> Raw, Callback</strong> ve <strong>Function</strong> formatlarında cevap döner.</td>
<td valign="top"><strong>http://api.search.live.net/json.aspx?AppId=</strong><em>YOUR_APPID</em><strong>&Market=en-US&Query=testing&Sources=web+spell&Web.Count=</strong><strong>1</strong></td>
</tr>
<tr>
<td valign="top"><strong>eXtended Markup Language(XML) </strong></td>
<td valign="top"><strong>SOAP</strong> formatını <span style="text-decoration: underline;">desteklemeyen</span> veya <strong>Siverlight</strong> gibi uygulamalarda tercih edilir. İstemcinin talepleri<strong> HTTP Get</strong> metoduna göre gideceğinden URL sınırı en büyük handikapı olarak görülebilir.</td>
<td valign="top"><strong>http://api.search.live.net/xml.aspx?AppId=</strong><em>YOUR_APPID</em><strong>&Market=en-US&Query=testing&Sources=web+spell&Web.Count=</strong><strong>1</strong></td>
</tr>
<tr>
<td valign="top"><strong>Simple Object Access Protocol(SOAP)</strong></td>
<td valign="top"><strong>XML</strong> modelindeki gibi URL sınır kısıtı yoktur. Ayrıca <strong>karmaşık tiplerin(Complex Type)</strong> ifade edilebilmesi, <strong>request/response</strong> nesne modelinin sağlanması gibi avantajları vardır. Özellikle masaüstü uygulamalar(Desktop Applications) veya servis bazlı uygulamalar için idealdir. C# gibi yüksek seviyeli dillerle kullanımı son derece kolaydır.</td>
<td valign="top"><strong>http://api.search.live.net/search.wsdl?AppID=</strong><em>YourAppId (Web Service Referansını ekleme adresidir)</em></td>
</tr>
</tbody>
</table>
<p>Görüldüğü gibi, Bing API' si için değerlendirilecek istemci talepleri, <strong>Json formatında,</strong> <strong>HTTP Get metodunda</strong> gönderilebilmektedir. Ama burada altı çizilmesi gereken ve benimde en çok ilgimi çeken <strong>SOAP</strong> modelidir. Öyleki, bu modelin uygulanması için istemci tarafının bir<strong> XML Web Service</strong> referansını kullanması yeterlidir. Bu, istemci tarafında managed bir kodun uygulanabilmesi anlamına gelmektedir. Asenkron çağrılar gerçekleştirebilir, strong tipler kullanabilir, hatta sonuç kümeleri üzerinde LINQ sorguları dahi yapılabilir.</p>
<blockquote>
<p>Bir zamanlar .Net üzerine eğitmenlik yapardım. İlk yıllarımda .Net 1.0 vardı ve Xml Web Service konusunda gerçek hayat örnekleri bulmakta zorlanırdık. Genellikle kendi servislerimizi yazar, çağırır ve ele alırdık. Yada popüler hava durumu servisi örneği. Ama gerçek hayat senaryolarında, çok basit olan ve bizim tarafımızdan yazılmamış bir Web Servisi nasıl değer kazanabilir,artık pek çok örneği ile görebilmekteyiz. İşte küçük bir örnek, Bing API tarafından kullanılan Live servisi...</p>
</blockquote>
<p>Öyleyse hiç vakit kaybetmeden <strong>acele acele</strong> bir örnek yapalım. <img title="Smile" src="/editors/tiny_mce3/plugins/emotions/img/smiley-smile.gif" alt="Smile" border="0" /> Bu acele örneğimizde basit bir <strong>Windows</strong> uygulamasına, aradığımız kritere uyan <strong>20</strong> resmi çekmeye çalışacağız. Bir başka deyişle <strong>SourceTypes.Image</strong> tipinden bir arama gerçekleştireceğiz. Yapmamız gereken ilk şey, <strong>Live Search</strong> servisine ait <strong>Xml Web Service</strong> referansını uygulamamıza eklemek olmalıdır. Aşağıdaki görüntüde olduğu gibi. Dilerseniz benim yaptığım gibi <strong>Web reference name</strong> alanının değerini aynen bırakabilirsiniz.</p>
<p><img src="/pics/2009%2f8%2fblg72_AddWebReference.gif" alt="" /></p>
<p><em><strong>Kişisel Not :</strong> Referans eklemesinden sonra <strong>Class Diagram</strong> görüntüsüne bakmanızı öneririm <img title="Sealed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-sealed.gif" alt="Sealed" border="0" /></em></p>
<p>Uygulamamızın Form tasarımını aşağıdaki gibi düzenleyebiliriz. Ben arama kutucuğunun sonucu olarak gelecek resim bilgilerini, alt tarafta yer alan <strong>FlowLayoutPanel</strong> bileşeni içerisinde <strong>PictureBox</strong> kontrolleri ile ifade etmeyi tercih ettim.</p>
<p><img src="/pics/2009%2f8%2fblg72_FormDesign.gif" alt="" /></p>
<p><strong>PictureBox</strong> kontrolümüzde, resmin arama sonuçlarından gelen tüm bilgilerinide saklamak istediğimden, aşağıdaki kod parçasında görülen <strong>ThumbImage</strong> isimli bir bileşen kullanmayı uygun gördüm.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Windows.Forms;
using WinClient.net.live.search.api;
namespace WinClient
{
class ThumbImage
:PictureBox
{
public ImageResult Result { get; set; }
}
}</pre>
<p>Dikkat edileceği üzere <strong>ImageResult</strong> tipinden bir özellik yer almaktadır. Bu <strong>özellik(Property)</strong>, arama sonucu servisden gelen sonuç kümesinde yer alan resim bilgilerini taşıyan tiptir. Kendi içerisinde, resmin <strong>Thumbnail Url, Media Url, Title, Width, Height</strong> vb... bilgilerini taşımaktadır. Biz bu bilgilerden faydalanıyor olacağız. Peki ama nasıl? İşte Form sınıfımızın tüm kod içeriği;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Windows.Forms;
// Varsayılan olarak SOAP tabanlı Live servisinin eklenmesi ile gelen namespace
using WinClient.net.live.search.api;
namespace WinClient
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnSearch_Click(object sender, EventArgs e)
{
pnlImages.Controls.Clear();
if (!String.IsNullOrEmpty(txtSearch.Text))
{
using (LiveSearchService searchService = new LiveSearchService())
{
#region Arama talebi oluşturulur
SearchRequest request = new SearchRequest
{
AppId = "{Size verilen AppId değeri}",
Query = txtSearch.Text,
Sources = new SourceType[] { SourceType.Image },
Adult = AdultOption.Strict,
AdultSpecified = true,
Image = new ImageRequest { Count = 20, CountSpecified = true, Offset = 0, OffsetSpecified = true }
};
#endregion
#region Arama sonucunun değerlendirilmesi
SearchResponse response = searchService.Search(request);
if (response.Image!=null &&
response.Image.Results.Length > 0)
{
foreach (ImageResult imgResult in response.Image.Results)
{
ThumbImage img = new ThumbImage
{
Result = imgResult,
ImageLocation = imgResult.Thumbnail.Url
};
img.Click += delegate(object obj, EventArgs args)
{
Form frm = new Form()
{
ControlBox=true
, MaximizeBox=false
,MinimizeBox=false
, Text=String.Format("{0} X {1} / {2} / {3} bytes",img.Result.Width,img.Result.Height,img.Result.Title,img.Result.FileSize)
};
PictureBox pb = new PictureBox {
ImageLocation =img.Result.MediaUrl
,Dock= DockStyle.Fill
};
frm.Controls.Add(pb);
frm.Show();
};
pnlImages.Controls.Add(img);
}
}
else
{
MessageBox.Show("Herhangibir sonuç bulunamadı", "Sonuç", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
#endregion
}
}
else
{
MessageBox.Show("Lütfen aradığınız resim ile ilişkili bir bilgi giriniz","Sonuç", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}</pre>
<p>İlk olarak <strong>LiveSearchService</strong> nesnesi örneklenir. Bu örnek tahmin edileceği üzere <strong>Search</strong> operasyonunu yerine getirecek olan <strong>proxy</strong> tipimizdir. Diğer yandan arama işlemi için başlangıç kriterlerinin belirtilmesi gerekir. Bu amaçla <strong>SearchRequest</strong> tipinden bir nesne örneği oluşturulmaktadır. Dikkat edileceği üzere <strong>Image</strong> tipinden bir arama istendiği belirtilmiş ve buna göre <strong>Image</strong> özelliğine yeni bir <strong>ImageRequest</strong> nesnesi atanmıştır. <strong>ImageRequest</strong> nesnesinde <strong>20</strong> resimlik bir sonuç kümesinin talep edildiği belirtilmektedir. <strong>SearchRequest</strong> sınıfı örneklenirken <strong>App Id</strong> değeri verilmektedir.</p>
<p>Hatırlayınız, bu değeri siz formu doldurduktan sonra alıyorsunuz. Önemli atamalardan biriside <strong>Query</strong> özelliği için yapılandır. Bu özelliğin değeri aranacak içeriği taşımaktadır. Bundan sonrası son derece kolaydır. <strong>LiveSearchService</strong> nesne örneğinin <strong>Search</strong> metoduna parametre olarak <strong>SearchRequest</strong> referansı atanır. Sonuçlar <strong>SearchResponse</strong> nesne örneğine gelir. Ardından <strong>SearchResponse</strong> nesne örneğinin <strong>Image</strong> özelliğinin <strong>Results</strong> koleksiyonundaki her bir <strong>ImageResult</strong> değerlendirilerek resim bilgilerinin alınması sağlanır. Elde edilen sonuçların her biri için bir <strong>ThumbImage</strong> bileşeni oluşturulur ve <strong>FlowLayoutPanel</strong> bileşeninin <strong>Controls</strong> koleksiyonuna eklenir. Uygulamanın çalışma zamanındaki örnek çıktısı aşağıda görüldüğü gibidir. Ben <strong>Ferrari</strong> kelimesi ile ilişkili resim dosyalarını arattım <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" />.</p>
<p><img src="/pics/2009%2f8%2fblg72_SampleRuntime.gif" alt="" /></p>
<p>Görüldüğü gibi minik resimlerden herhangirine tıklandığında orjinal halide yeni bir <strong>Form</strong> içerisinde gösterilebilmektedir. Buna ek olarak resim ile ilişkili bir kaç basit bilgide Form' un başlığında gösterilmektedir. Resmin boyutları, başlığı ve büyüklüğü. Ne kadar basit öğle değil mi? <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Bu arada <strong>Bing API</strong> ile ilişkili dökümanı indirdiğinizde içerisinde <strong>JSON, XML ve SOAP</strong> modellerinin her biri için ayrı ayrı yapılmış detaylı örnek anlatımları ve projeler olduğunu göreceksiniz. Bunları incelemenizi şiddetle tavsiye ederim. Peki bu acele örnekte yapmadıklarımız?</p>
<ul>
<li><strong>Exception kontrolü</strong><em>(Örneğin bağlantı problemelerinde yada resmin elde edilememesinde yaşanabilecek sıkıntıları handle etmek gerekir)</em></li>
<li>Asenkron arama metodu uygulanabilir ama bu durumda <strong>Illegal Cross Thread Exception</strong> hatasından kaçınmak gerekir.</li>
</ul>
<p>Bunlarda size görev olsun. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
2009-08-25T11:15:00+00:00
xml web services
c#
bsenyurt
Bir süredir WCF 4.0 ile birlikte gelen yenilikleri sizlere aktarmaya çalışıyorum. Son olarak Routing Service ile ilişkili bir giriş yazımız olmuştu. Bu konu ile ilişkili örnek en kısa sürede sizlerle olacak. Ne varki konu biraz zorlu. Undecided Bu yüzden bende yüksek lisans eğitimi aldığım yıllarda çok sevgili hocam Halil Seyidoğlu' nun bir açıklamasını uygulamaya karar verdim. Kendisi bize "Bilimsel Araştırma ve Yazma" dersinde şöyle seslenmişt; "Bir tez konusunu araştırırken çok zorlu yollardan geçersiniz. Tezin bir noktasında tıkandınız mı? O zaman ara verin...Tatile çıkın...Bir süreliğine uzaklaşın..."
https://www.buraksenyurt.com/pingback.axd
https://www.buraksenyurt.com/post.aspx?id=73048ad9-ddc0-4419-9253-ff54345275e1
1
https://www.buraksenyurt.com/trackback.axd?id=73048ad9-ddc0-4419-9253-ff54345275e1
https://www.buraksenyurt.com/post/Merhaba-Bing-API-20#comment
https://www.buraksenyurt.com/syndication.axd?post=73048ad9-ddc0-4419-9253-ff54345275e1