Burak Selim Senyurt(MVP)
Matematik Mühendisi bir .NET Severin Yazıları...

Screencast - WCF Data Services - Projections

Pazartesi, 8 Mart 2010 11:10 by bsenyurt

Merhaba Arkadaşlar,

Yazılımcı bile olsak bu arada sırada spor yapmadığımız anlamına gelmemeli. Bende çalışma arkadaşlarım ile sık sık spor aktivitelerinde bulunuyorum. Zaman zaman parke zeminde o muhteşem NBA yıldızları gibi giyinerek basketbol oynuyor, zaman zaman Ping Pong...Geçtiğimiz günlerde ise bir halı saha maçı organizasyonundaydım. Bu organizasyonun bitmesinden hemen sonra duşumu aldım, günlük kıyafetlerimi giydim ve akşamın sekizinde bilin bakalım nereye gittim...Şirkete Laughing Deli mi bu adam...Eve gitse ya...Amacı ne? Nitekim maç sırasında sürekli aklımda olan ve beni dürten bir mesele vardı. Uzun zamandır çekmek istediğim bir görsel ders için şu saatlerde sessiz olan şirket en ideal mekandı.

NedirTv? aracılığıyla hazırladığımız bu görsel dersimizde, WCF Eco System' in bir parçası olan WCF Data Service' lerinde Projections sorgularının nasıl kullanılabileceğini incelemeye çalışıyoruz. Aslında kod adı Astoria olan Ado.Net Data Service' lerin 1.5 CTP2 sürümünde de duyurulan bu yetenek, zaten .Net Framework 4.0 içerisine gömülü olarak gelen WCF Data Service' ler için standartlaştırılmış bir özellik. Bu amaçla hazırladığımız ve 7,5 dakikayı aşmayan görsel dersimizin faydalı olacağını ümit ediyorum. İyi seyirler dilerim.

Dosya Boyutu : 14.3 Mb

Süre : 7:35

İzlemek veya Download Etmek için 

WCF WebHttp Services - Routing

Pazartesi, 8 Mart 2010 08:45 by bsenyurt

Merhaba Arkadaşlar,

Geçtiğimiz aylarda yurdumuzun en güzel şehirlerinden birisi olan İstanbul' da, oldukça soğuk ve kar yağışlı günler geçirdik. Yandaki resimde görülen manzara çalıştığım ARI 1 binasının yürüyüş yolu üzerinde çok da yeni olmayan, dokunmatik ekran, Windows Mobile gibi ileri özellikleri bulunmayan ancak Carl Zeiss mercekli Sony Ericsson K810i marka cep telefonum tarafından çekilmiştir. 3.1 Megapiksel ölçekli çekilen fotoğrafı kaliteli yapan ise elbetteki Carl Zeiss mercek. İnsan böyle zamanlarda eğer şartlar yerindeyse(çay, kahve, sıcak ve sessiz bir ortam, hızlı bir internet bağlantısı) işiyle ilgili pek çok konuda araştırma fırsatı bulabiliyor. Malum böyle havalarda sizde benim gibi evden çıkmamayı veya mesai sonrası şirkette bir kaç saat durmayı tercih edinenlerdenseniz, yapılacaklar listesinin belkide en başında yenilikleri araştırmak vardır diye düşünüyorum. Malum bir süredir de WCF Eco System' in önemli parçalarından birisi olan WebHttp Service' lerini incelemekte olduğumuza göre yine bu alanda ilerleyerek devam edebiliriz. Bu günkü konumuz ise WCF WebHttp servislerinde yönlendirme(Routing) işlemleri olacak.

Pek tabi, bir WCF REST Service Application içerisinde birden fazla WebHttp Service sınıfı konuşlandırılabilir. Bu çoğunlukla tek bir sınıfın var olduğu hallerde zaman içerisinde artan fonksiyon sayısı nedeniyle kavramsal bütünün bozulmasını engellemek amacıyla alınan bir tedbir olarak düşünülebilir. Aslında gerçek hayatta söz konusu kavramsal bütünlüğün ayrıştırılması ile ilişkili pek çok başarılı örnek yer almaktadır. Örneğin Sql Server 2005 ile gelen meşhur Adventure Works veritabanını göz önüne alalım. Burada bildiğiniz üzere çok sayıda tablo çeşitli şemalara(Schema) ayrılmıştır. Production, HumanResource, Sales vb...Böylece veritabanı alan modelinin(Domain Model) kavramsal olarak kolay bir şekilde ayrıştırılması mümkün olmaktadır. İşte benzer durum servis sınıflarının içeriğini oluşturan fonksiyonlar için de geçerli olabilir. Buna göre operasyonların ayrı servis sınıfları altında toplanıyor olması Adventure Works örneğindekine benzer kavramsal bir ayrımın yapılabilmesi manasına gelmektedir. Peki bir servisin yürüttüğü operasyonları sınıf bazında ayrıştırmanın uygulanışında nelere dikkat edilmesi gerekmektedir?

Herşeyden önce WebHttp Service' leri URI üzerinden gelen HTTP taleplerini değerlendirmektedir. Yani servise gelen bir talep, servis sınıfı içerisindeki bir operasyon ile ilişkilendirilmektedir. Bu noktada WCF WebHttp Service' lerinin konuşlandırıldığı Web uygulamasının global.asax içeriğinin büyük önemi vardır. Nitekim bu dosya içerisinde gelen talep için bir yönlendirme yapılması mümkündür. Bu amaçla RegisterRoutes isimli metoddan yaralanılır. Bir başka deyişle servisleri barındıran Web uygulaması ayağa kaldırıldığında, hangi URI taleplerinin hangi servislere yönlendirileceği bellidir. URI içerisinde yer alan operasyonel yönlendirmeler ise ilgili servis sınıfının metodlarına ait WebGet veya WebInvoke nitelikleri yardımıyla belirlenmektedir. Dolayısıyla istemcilerden gelecek olan taleplerin hangi servise yönlendirileceği sorusunun cevabı global.asax dosyası içerisinde verilmektedir. Hemen küçük bir not düşelim; bildiğiniz üzere Web taleplerinin daha etkin bir şekilde yönlendirilebilmesi yeteneği Asp.Net 4.0 ile birlikte gelmektedir. Bu sebepten geliştirilen WCF WebHttp servisinin Asp.Net uyumluluğu modunda(Asp.Net Compatibility Mode) çalıştırılıyor olması önemlidir.

Dilerseniz konuyu daha net kavrayabilmek adına basit bir örnek ile devam edelim. Bu amaçla Visual Studio 2010 Ultimate RC sürümü üzerinden geliştireceğimiz WCF REST Service Application'a ait Solution içeriğini aşağıdaki gibi tasarladığımızı düşünelim.

Görüldüğü üzere CalculationService ve ProductionService isimli iki sınıfımız bulunmaktadır. Bu servis sınıfları içerisinde çok basit iki operasyon yer almakta ve her ikiside HTTP Get metodlarına göre cevap vermektedir. ProductionService sınıfı içerisinde Product tipinden değer döndüren bir arama operasyonu yer almaktadır. Diğer yandan CalculationService sınıfı içerisinde bir ürün fiyatına hangi günde bulunulduğuna göre indirim yapan ve sonuç değerini gösteren bir operasyon yer almaktadır. Yönlendirme teorimize göre servis uygulamasına gelen talepleri CalculationService ve ProductionService tipleri üzerine dağıtmak istiyoruz. Bunun için global.asax dosyasında gerekli kodlamaları yapmamız gerekecektir. Ama öncesinde CalculationService, ProductionService ve Product tipi içeriklerimize bir bakalım.

Sınıf diagramımız;

Product sınıfımız;

namespace Lesson5
{
    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public decimal ListPrice { get; set; }
    }
}

ProductionService sınıfımız;

using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace Lesson5
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class ProductionService
    {
        private static List<Product> Products = new List<Product>
        {
            new Product{ ProductId=1023, Name="Microsoft Optical Mouse", ListPrice=34.95M},
            new Product{ ProductId=1045, Name="Logitech Optical Mouse", ListPrice=35.45M},
            new Product{ ProductId=1029, Name="KeyMaster Wireless Keyboard", ListPrice=55.99M},
            new Product{ ProductId=9802, Name="Obi Wan Kneobi Jedi Light Saber", ListPrice=334.45M},
        };

        [WebGet(UriTemplate = "Products/{ProductId}")]
        public Product GetProduct(string ProductId)
        {
            Product prd=null;

            try
            {
                prd = (from p in Products
                       where p.ProductId.ToString() == ProductId
                       select p).First();
            }
            catch
            {          
                // Bir Product bulunamama olasılığına karşın HTTP statü kodu 404 döndürülür
                throw new WebFaultException(System.Net.HttpStatusCode.NotFound);
            }

            return prd;
        }
    }
}

CalculationService sınıfımız;

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace Lesson5
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class CalculationService
    {
        [WebGet(UriTemplate = "Discount/{ListPrice}")]
        public decimal CalculateDiscountListPrice(string ListPrice)
        {
            decimal decreasedListPrice = 0;
            decimal currentListPrice = 0;

            // Eğer string olarak gönderilen ListPrice değeri decimal tipe dönüşütürülemesse BadRequest tipinden bir statü kodu döndürülmesi sağlanır.
            if (!decimal.TryParse(ListPrice, out currentListPrice))
                throw new WebFaultException(System.Net.HttpStatusCode.BadRequest);

            switch (DateTime.Now.DayOfWeek)
            {
                case DayOfWeek.Friday:
                    decreasedListPrice = currentListPrice-(currentListPrice * 0.1M);
                    break;
                case DayOfWeek.Monday:
                    decreasedListPrice = currentListPrice-(currentListPrice * 0.2M);
                    break;
                case DayOfWeek.Saturday:
                    decreasedListPrice = currentListPrice;
                    break;
                case DayOfWeek.Sunday:
                    decreasedListPrice = currentListPrice;
                    break;
                case DayOfWeek.Thursday:
                    decreasedListPrice = currentListPrice-(currentListPrice * 0.3M);
                    break;
                case DayOfWeek.Tuesday:
                    decreasedListPrice = currentListPrice-(currentListPrice * 0.5M);
                    break;
                case DayOfWeek.Wednesday:
                    decreasedListPrice = currentListPrice-(currentListPrice * 0.2M);
                    break;
            }

            return decreasedListPrice;
        }
    }
}

Ve gelelim projemizin en önemli kısmına. Yönlendirme ile ilişkili olarak global.asax dosyasında yer alan RegisterRoutes metodunun içeriğini aşağıdaki gibi değiştirmemiz yeterli olacaktır.

using System;
using System.ServiceModel.Activation;
using System.Web;
using System.Web.Routing;

namespace Lesson5
{
    public class Global
        : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }

        private void RegisterRoutes()
        {
            // WebServiceHostFactory nesnesi örneklenir.
            WebServiceHostFactory hostFactory = new WebServiceHostFactory();

            // Route tablosuna gerekli eşleştirme bilgileri eklenir.
            // Gelen talep Productions içinse ProductionService servis tipi ile ilişkilendirilir.
            // Gelen talep Calculations içinse CalculationService servis tipi ile ilişkilendirilir.
            RouteTable.Routes.Add(new ServiceRoute("Productions", hostFactory, typeof(ProductionService)));
            RouteTable.Routes.Add(new ServiceRoute("Calculations", hostFactory, typeof(CalculationService)));
        }
    }
}

Uygulama başlatıldığında Application_Start metoduna girilecektir. Bu metod içerisinde ise RegisterRoutes fonksiyonu çağırılmaktadır. RegisterRoutes metodu içerisinde dikkat edileceği üzere iki ServiceRoute tipinin örneklenmesi ve bunların RouteTable üzerindeki Tables koleksiyonuna eklenmesi sağlanmaktadır. Buna göre servise gelen talepler aşağıdaki şekilde görüldüğü üzere eşleşen tiplere yönlendirilecektir.

Hemen çalışma zamanı sonuçlarına bir bakalım. Örneğin http://localhost:10860/Productions/Products/1029 talebinde bulunduğumuzda aşağıdaki sonuçlar ile karşılaşırız. Görüldüğü üzere talep ProductionService' e yönlendirilmiştir. (Tabi var olmayan bir ProductID talebi girildiğinde HTTP Status Code 404 NotFound ile karşılaşırız. WebFaultException tipinin kullanımının anlatıldığı yazımızı hatırlayalım lütfen Wink )

Diğer yandan http://localhost:10860/Calculations/Discount/120,45 şeklinde bir talepte bulunduğumuzda ise CalculationService' e yönlendirildiğimizi görebiliriz. (Yine decimal tipe dönüştürülemeyen bir talep gönderildiğinde tahmin edileceği üzere HTTP Status Code 400 Bad Reuqest ile karşılaşırız.)

Sonuç olarak UriTemplate' lerin ilgili servis operasyonları ile eşleştirilmesi çok daha kolaylaştırılmıştır. Öncelikle olarak gelen talebin hangi servis ile ilişkili olduğu noktasında Route Table devreye girmektedir. Ardından talep servise gelir. Servis ise URI içeriğine bakara uygun operasyonun çağırılması ile ilgilenir. Böylece geldik bir konumuzun daha sonuna. Bir sonraki yazımızda görüşünceye dek hepinize mutlu günler dilerim.

Lesson5_RC.rar (24,11 kb) [Örnek Visual Studio 2010 Ultimate Beta 2 Sürümünde geliştirilmiş ancak RC sürümü üzerinde de test edilmiştir]

WCF WebHttp Services - Error Handling

Cuma, 5 Mart 2010 08:10 by bsenyurt

Merhaba Arkadaşlar,

Bu yazımızda WCF Eco System' in bir parçası olan WebHttp Service' lerinde hata yönetimini(Error Management) etkili bir şekilde nasıl ele alabileceğimizi incelemeye çalışıyor olacağız. WCF WebHttp Service' leri üzerinden çağırılan bir servis operasyonundan, istemci tarafına kendi insiyatifimizde hata mesajları gönderilmesini sağlayabiliriz. Üstelik bu mesajları bilinen HTTP durum kodları(HTTP Status Code) çerçevesinde yayınlayabiliriz. Bu tip bir isteğin çeşitli sebepleri olabilir. Hemen bir gerçek hayat senaryosu üzerinden ilerleyerek bu basit konuyu pekiştirmeye çalışalım. Bu amaçla Visual Studio 2010 Ultimate RC sürümü üzerinde geliştirdiğimiz ve  aşağıdaki kod içeriğine sahip bir WCF REST Service Application projemiz olduğunu düşünelim.

using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace ServerApp
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class AzonBookService
    {
        static List<Book> books = new List<Book>
            {
                new Book{ Id=1002, Name="Programming WCF 4.0",ListPrice=12.00M},
                new Book{Id=9034,Name="Pro Asp.Net 4.0",ListPrice=34.90M},
                new Book{Id=4560,Name="Algebra",ListPrice=122.39M},
                new Book{Id=1200,Name="C# 3.5 Cookbook",ListPrice=14.45M},
                new Book{Id=1201,Name="Pro C# 4.0 and .Net Framework 4.0",ListPrice=34.05M},
                new Book{Id=1201,Name="Beginning Ado.Net Entity Framework",ListPrice=14.55M}
            };

        [WebGet(UriTemplate = "/{firstLetter}")]
        public List<Book> GetBooks(string firstLetter)
        {
            return (from book in books
                   where book.Name.StartsWith(firstLetter)
                   select book).ToList();
        }
    }

    public class Book
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal ListPrice { get; set; }
    }
}

AzonBookService çok basit ve tek bir operasyona sahiptir. GetBooks isimli operasyon HTTP Get metoduna göre hizmet vermekte olup baş harfleri firstLetter parametresin ile gelen değer ile başlayan bir List<Book> koleksiyonunu geriye döndürmektedir. Bu servisi bir tarayıcı uygulama üzerinden test ettiğimizde ve örneğin Pro kelimesi ile başlayan kitapları elde etmek istediğimizde aşağıdaki ekran görütüsündekine benzer sonuçlar ile karşılaşırız.

Bu noktaya kadar zaten herhangibir sorun bulunmamaktadır. Ancak örneğin Ç harfi ile başlayan kitapların listesini elde etmek istediğimizde, aşağıdaki ekran görüntüsü ile karşılaşırız.

Şimdi bu noktada geliştirici olarak bir karar verebiliriz. İstemci tarafına bu şekilde boş bir XML içeriği döndürmemiz halinde, istemci tarafının Ç harfi ile başlayan kitapların olmaması durumunu ele alması gerekmektedir. Yani istemci tarafına ek bir iş yükü getirmiş olabiliriz. Nitekim istemcinin dönen listenin eleman sayısına bakara bir karar vermesi gerekmektedir. Diğer yandan istemciyi bilinçli bir şekilde uyarabiliriz de. Nasıl mı? Servis tarafındaki çalışma zamanında üreteceğimiz ve o anki vakaya uygun bir istisna(Exception) ile. Tabiki bu istisna mesajı servis bazlı bir yapı üzerinden ele alınacağı için istemci tarafına gönderilecek paketin içerisine gömülecektir. WCF WebHttp Service' lerinde bu tip istisnaları ele almak için WCF tarafından bildiğimiz FaultException tipinden türeyen WebFaultException sınıfından yararlanılır.

System.ServiceModel.Web isim alanı altında yer alan WebFaultException tipinin normal ve generic olan versiyonları bulunmaktadır. İlgili tipleri kullanımları son derece basittir. Yukarıdaki senaryomuza göre istemciye aradığı kriterlere uygun bir içerik bulunamadığını bildirmek amacıyla, GetBooks isimli servis operasyonunu aşağıdaki gibi değiştirebiliriz.

[WebGet(UriTemplate = "/{firstLetter}")]
        public List<Book> GetBooks(string firstLetter)
        {
            var result=(from book in books
                   where book.Name.StartsWith(firstLetter)
                   select book).ToList();

            if (result.Count == 0)
                throw new WebFaultException<string>("Talep edilen kelime ile başlayan kitaplar sistemde mevcut değiller.", System.Net.HttpStatusCode.NotFound);

            return result;
        }

Burada dikkat edileceği üzere sonuç listesinin eleman sayısı kontrol edilmiş ve eğer 0 ise WebFaultException tipinden bir istisna mesajı fırlatılması sağlanmıştır. WebFaultException tipinin örneklenmesi sırasında dikkat edilmesi gereken hususlardan biriside HttpStatusCode.NotFound Enum sabiti değerinin verilmesidir. Bu şekilde istemci tarafına hangi HTTP durum kodunun(Status Code) gönderileceği belirlenmektedir. Tahmin edeceğiniz üzere pek çok HTTP Status Code değeri bulunmaktadır.

Aslında tam liste içeriği şudur Wink Accepted, Ambiguous, BadGateway, BadRequest, Conflict, Continue, Created, Expectation Failed, Forbidden, Found, GatewayTimeout, Gone, HttpVersionNotSupported, InternalServerError, LengthRequired, MethodNotAllowed, Moved, MovedPermanently, MultipleChoices, NoContent, NonAuthoritativeInformation, NotAcceptable, NotFound, NotImplemented, NotModified, OK, PartialContent, PaymentRequired, PreconditionFailed, ProxyAuthenticationRequired, Redirect, RedirectKeepVerb, RedirectMethod, RequestedRangeNotSatisfiable, RequestEntityTooLarge, RequestTimeout, RequestUriTooLong, ResetContent, SeeOther, ServiceUnavailable, SwitchingProtocols, TemporaryRedirect, Unauthorized, UnsupportedMediaType, Unused, UseProxy

Operasyonumuzu bu yeni haliyle denediğimizde ise tarayıcı uygulama üzerinde aşağıdaki şekilde görülen çıktı ile karşılaşırız.

ki bu son derece doğaldır.

Nitekim zaten HTTP 404 mesajının istemci tarafına gönderilmesi sağlanmaktadır. WebFaultException<T> sınıfının örneklenmesi sırasında T parametresi de önemlidir. Örneğimizde basit bir string tipi kullanılmıştır. Peki ya kullanıcı tanımlı bir tip buraya dahil edilebilir mi? Gelin hem bu durumu hemde istemci uygulamanın geliştiriciler tarafından yazılması halinde söz konusu hata mesajlarının nasıl ele alındığı örneğimizi güncelleyerek irdelemeye çalışalım. Bu amaçla servisimizi aşağıdaki hale getirelim.

...Kodun diğer kısmı
       
        [WebGet(UriTemplate = "/{firstLetter}")]
        public List<Book> GetBooks(string firstLetter)
        {
            var result=(from book in books
                   where book.Name.StartsWith(firstLetter)
                   select book).ToList();

            if (result.Count == 0)
                throw new WebFaultException<ErrorInformation>(
                    new ErrorInformation { SearchLetter = firstLetter, SearchTime = DateTime.Now, Summary = "Talep edilen kelime ile başlayan kitaplar sistemde mevcut değiller." }
                    , System.Net.HttpStatusCode.NotFound);

            return result;
        }
    }

    public class ErrorInformation
    {
        public string SearchLetter { get; set; }
        public DateTime SearchTime { get; set; }
        public string Summary { get; set; } 
    }

Bu kod parçasında WebHttpException<ErrorInformation> tipinden bir nesne örneklenmiştir. Buna göre istemci tarafına bu içeriğin XML veya JSON formatında gönderilmesi mümkündür. Gelelim istemci tarafının kodlarına. Nitekim bir şekilde servis tarafından gelen içeriği kontrol atlına almamız gerekmekte.

using System;
using Microsoft.Http;

namespace ClientApp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (HttpClient client = new HttpClient("http://localhost:12654/Azon/"))
            {
                HttpResponseMessage response=client.Get("Ç");

                Console.WriteLine("Http Status Code : {0}\n",response.StatusCode.ToString());
                Console.WriteLine("Content : {0}\n",response.Content.ReadAsString());

            }
        }
    }
}

Ç harfi ile başlayan kitapların elde edilmesi için bir talep oluşturulmakta ve bu talep Get metodu yardımıyla servis tarafına gönderilmektedir. Get metodunun çıktısı HttpResponseMessage tipindendir. Elde edilen HttpResponseMessage nesne örneğinin StatusCode özelliği yardımıyla servis tarafında üretilen HttpStatusCode Enum sabitinin değeri elde edilir. Diğer yandan eğer istemci tarafından bir hata oluşuyorsa WebFaultException nesnesinin oluşturulması sırasında kullanılan ErrorInformation nesne örneğinin serileştirilmiş hali Content özelliği üzerinden elde edilebilmektedir. Buna göre çalışma zamanı çıktısı aşağıdaki gibi olacaktır.

Görüldüğü üzere servis operasyonu içerisinde üretilen ErrorInformation bilgisi istemci tarafına XML formatlı olacak şekilde aktarılmıştır. Sonuç olarak olası veya beklenen hatalar karşısında istemci tarafına uygun bir bildirim yapılması HTTP durum kodları bazında mümkündür. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Lesson4_RC.rar (174,57 kb) [Örnek Visual Studio 2010 Ultimate Beta 2 Sürümünde geliştirilmiş ancak RC sürümü üzerinde de test edilmiştir]

Screencast - AJAX Enabled WCF Services

Perşembe, 4 Mart 2010 10:45 by bsenyurt

Merhaba Arkadaşlar,

Görsel derslerimize kaldığımız yerden devam ediyoruz. Bu sefer elimizdeki materyaller bir WCF Service, Asp.Net Web Uygulaması ve AJAX. Bunları bir arada düşündüğümüzde ise karşımıza AJAX Enabled WCF Service kavramı çıkıyor. Bildiğiniz üzere Asp.Net uygulamalarında AJAX imkanları kullanılabilmekte ve bu sayede kısmi olarak post işlemleri gerçekleştirilebilmekte. Çok basit anlamda bir sayfanın tamamını sunucuya göndermeden sadece istenilen parçaların gönderilmesi ve sonuçlarının ele alınabilmesi mümkündür. Tabi sonuçların istemci tarafında ele alınması gerekmekte(Örneğin Javascript ile). AJAX Destekli WCF Servislerinde ise herhangibir servis operasyonunun çağrısı sırasında, servisi çağıran web sayfasının tamamının sunucuya gönderilmemesi imkanı kazanılmaktadır. AJAX Destekli WCF Servislerinin kullanıldığı pek çok senaryo söz konusudur. En basit haliyle otomatik metin tamamlama kabiliyetine sahip kontroller için bu teknikten yararlanılabilir. Bizde görsel dersimizde konu olarak bebek adlarını(Baby Names) ele almaya çalışacağız. Upss!!! Bebek Adları mı? Wink İzleyelim ve görelim.

Video Boyutu : 24 Mb

Süre : 14:06

Download Etmek veya İzlemek için

WebApplication2.rar (22,09 kb)

Screencast - Workflow Foundation 4.0 Switch Aktivite Bileşeni [RC]

Pazartesi, 1 Mart 2010 09:35 by bsenyurt

Merhaba Arkadaşlar,

Bildiğiniz üzere bir süre önce .Net Framework 4.0 RC sürümü yayınlandı. Bu da RTM ve Release sürüme çok yaklaştığımızı göstermekte. RC(Release Candidate) sürümünün önceki Beta sürümlerine göre daha tutarlı olduğunu söyleyebiliriz. Ancak yine de bu görsel dersimizde anlatacaklarımız ile ilişkili olarak Bug Fix' ler veya farklı güncelleştirmeler söz konusu olacaktır. Peki ya biz bu görsel dersimizde neyi ele almaktayız? Wink

Workflow Foundation 4.0 içerisinde yer alan Built-In Activity bileşenleri arasında bir programlama dilinin temel özelliklerinin de çoğu yer almakta aslında. Söz gelimi ForEach<T>, While, If, DoWhile, Assign, InvokeMethod, WriteLine ve benzerleri gibi aktiviteler göz önüne alındığında, değişken ataması, metod çağırılması, döngü kurulması veya koşullu kontrollerin yapılması son derece kolay. Bu anlamda, WF 4.0 içerisinde yer alan aktivite bileşenlerinden bir tanesi de Switch. C# dilinden aşina olduğumuz bu koşul ifadesinin mantığını, Workflow tiplerinde de kullanabilmekteyiz. NedirTv? katkılarıyla gerçekleştirdiğimiz bu görsel dersimizde Switch aktivite bileşeninin özel .Net tipleri için nasıl değerlendirilebileceğini incelemeye çalışmaktayız. Hepinize keyifli seyirler dilerim.

[Görsel derste yer alan örneğimiz Visual Studio 2010 Ultimate Beta 2 sürümünde geliştirilmiş ve test edilmiştir.]

Dosya Boyutu : 24.5 Mb

Süre : 13:43

İzlemek veya Download etmek için

UsingSwitch.rar (57,95 kb)

Tags:   , ,
Categories:   WF 4.0 RC
Actions:   E-mail | del.icio.us | Permalink | Yorumlar (2) | Comment RSSRSS comment feed
Bookmark and Share

Yazılımcının Kendi Kendini Eğitmesi

Pazartesi, 1 Mart 2010 08:00 by bsenyurt

Merhaba Arkadaşlar,

İster üniversite öğrencisi olun ister yeni mezun, yazılım sektörünün henüz başındaysanız eğer, kendinizi yandaki şekilde görülen yolun başında bekleyen birisine benzetebilirsiniz. Ne yolun uzunluğu bellidir ne de gidebileceğiniz yönler. Açıkçası buna baştan karar verebilmek çok zordur. Yaşantınızı ektileyen pek çok neden bu belirsizliğe sebebiyet verebilir. Hatta yazılım alanında hangi yöne doğru ilerleyeceğinize karar verdiğinizde aradan bir kaç yıl geçmiş olabilir. Tüm bu yaşam döngüsü içerisinde unutlmaması gereken bir noktada sizin öğrenme süreçlerinizdir. Pek çok yazılım sevdalısı arkadaşımız çabucak panikleyip bir yerlerden eğitim almaya çalışabilir. Bunun gerekli olduğu veya olmadığı durumlar vardır. Açıkçası Mühendislik nosynonunu Üniversite öğrenimi sırasında kazanmış olanlar avantajlıdır. Ancak onlar içerisinde bile eğitim almak için parasını harcamaktan çekinmeyen kişiler olabilir. Bu yazımızda yine teknik olmayan bir konuya değiniyor olacağım. Sizin bir yazılımcı olarak kendi kendinizi nasıl eğitebileceğinizi anlatmaya çalışacağım. Uzun bir süre eğitimcilik yaptığım için yazıda yer alan ip uçlarını faydalı bulacağınızı düşünüyorum. Tavsiyelerime kulak verin. Wink

Yaşananlardan : 90 lı yılların başlarında üniversite öğrencisiydim ve bilgisayar programcılığına olan merakım her geçen gün katlanarak artıyordu. Açıkçası 64 Kb sınırı altında yaşayan ve oyun yazan programcılara fazlasıyla imreniyordum. O yıllarda Türkçe yazılım kitaplarını bulmak zordu. Şimdi çok kitabımız var ancak aradan kaliteli olanları seçmek istediğinizde aslında çok az kitabımız var. Yabancı kitapları Türkiye' ye getirtmekte bir meseleydi. Özellikle fiyatları düşünüldüğünde. Yurt dışı kanalı ile tedarik ettiğim ilk bilgisayar kitabım Delphi 2.0 Unleashed idi. (Eski bir Delphi programıcısı olduğumu ama Anders Hejslberg' in izinden gittiğimi belirtmek isterim) 1400 sayfaya yaklaşan bu kitabı Taksim' de bulunan Elit kitabevinden tedarik etmiştim. O günü çok net hatırlıyorum. Ahşap tabanda yürürken raflarda gördüğüm sayısız kitabın çoğunu satın almak istemiştim. Ama elimde o kadar çok param yoktu. Yine de isabetli bir atış yapmaya çalışmış ve gerçekten ilgilendiğim konuya ait bir tanesini tedarik edebilmiştim. Bu bulunmaz bir nimet gibiydi.

Kitaplar

Yazılımcıların en büyük dertlerinden birisi de çok hızlı gelişen ve sürekli olarak bizi ötelemeye zorlayan teknoloji. Programlama dilleri, Framework' ler, yazılım metodolojileri sürekli olarak değişmekte veya yenilenmekte. Bunun için uzağa gitmemize gerek yok. C#' ın bir kaç sene içerisinde 4ncü versiyonuna nasıl geldiğini gayet iyi biliyoruz. Dolayısıyla bir yazılımcının çok sık kitap okuması ve takip etmesi gerekiyor. Bu anlamda Amazon gibi Amerika veya İngiltere üzerinden kitap getirtebilmemizi sağlayan sitelerin sunduğu ingilizce kaynaklar hem profesyonellikleri hem de anlatımları yönünden son derece kuvvetli ve yeterli. Size tavsiyem bir kaç arkadaş birleşip birden fazla kitap getirterek taşıma ücretini mümkün olduğunca hafifletmeniz Wink

Yaşananlardan : Üniversitedeki eğitimimi Türkçe almıştım. Mezun olduğumda 1 senelik ingilizce hazırlık eklenmişti. Aslında tüm eğitim hayatım boyunca devlet okullarında öğrenci olmuştum. Ne acıdır ki, orta okul yıllarında hoca yetersizliğinden veya anlaşmazlıklardan dolayı ingilizce derslerimizin yarısından çoğu boş geçmişti. Hal böyle olunca insan çok doğal olarak yabancı dil sorununu tek başına halletmek zorunda kalıyor. Az önce bahsettiğim Delphi 2.0 kitabı bir kaç ay içerisinde kara kalem çalışmasına dönmüştü. Çünkü bilmediğim her kelimenin yanına kurşun kalem ile ne anlama geldiğini yazmıştım. Bu sonraki kitapta, ondan sonrakinde ve sonrakinde de devam etti. Ama bir süre sonra altı çizili kelimeler azalmaya başladı. Yani biraz azmetmem gerekmişti. Bu noktada pek çok rakibinizden geride kaldığınızı düşünebilirsiniz. Ama inanın bir noktadan sonra onları yakalayabilir ve hatta kazandığınız çalışma disiplini ile geçebilirsiniz. Çünkü sıkılmadan yapacağınız ve sözlükten bulduğunuz kelimeleri yazarak harcayacağınız zaman içerisinde standart bir disipline sahip olursunuz. Bu disiplinin içeriği basittir. Sıkılmamak, konsantre olmak, hedefe ulaşmak. Ödülü ise basittir; okuduğunuzu anlamak. Laughing

Tabi burada mutlaka dikkat edilmesi gereken bir nokta var. Çok fazla kitap almaktan ziyade isabetli kitapları seçmek daha önemlidir. Yoksa yandaki resimde görüldüğü üzere kitap sayfaları arasında rahatlıkla kaybolabilir ve işi daha da karmaşık bir hale sokabilirsiniz. Bu noktada belkide daha tecrübeli kişilere danışmak uygun bir davranış olarak görülebilir. Ne de olsa artık günümüzde pek çok yetkin kişiye mailler aracılığıyla ulaşabilmekteyiz.

Eğitim

Kitaplar her zaman için faydalı olan kaynaklardandır ama tek başlarına yeterli olmayabilirler. Çoğu zaman konuyu daha uzman birisinden dinlemek isteyebilirsiniz. Dinlediğiniz kişinin bu anlamda tecrübeli olması geçmiş proje deneyimlerini konu anlatımları üzerine serpiştirmesi de çok önemlidir. Hatta konu ile ilişkili olarak lab çalışması yapılabilmesi size çok fazla değer katacaktır.

Yaşananlardan : Uzun süre bir eğitim firmasında yazılım eğitmeni olarak görev aldım. Eğitimler sırasında özellikle kitaplardan anlatılan konularda öğrencilerimin en çok yakındıkları veya sevmedikleri konu lab çalışmalarının olmasıydı. Aslında Microsoft tarafından sunulan kitaplarda yer alan lab çalışmalarının çoğu, konu ile ilişkili olarak baştan sona bir projenin tamamlanmasını, öğrenilenlerin pekiştirilmesini, hangi malzemeler ile neler yapılabileceğinin görülmesini sağlamaktaydı. Üstelik bu sağlanırken gerçek hayat pratikleri de kazanılmaktaydı.Bu nedenle aldığınız eğitimler içerisinde lab çalışmaları var ise bunları görmezlikten gelmeyin.

Açıkçası bu tip eğitmen bulduğunuzda yakasını eğitim süresi boyunca bırakmamanızda ve söylediklerini yapmanızda fayda vardır. Ne yazık ki günümüzde pek çok eğitim firması işlerini su istimal etmektedir. Açıkçası bu işi hafife alanlardan tutunda, tamamen ticari çıkarlara dönüştüren, rekabet etmek isterken eğitimin kalitesini düşüren firmalar söz konusudur. Ancak tüm bu firmalar her zaman için kendilerinin en iyi eğitmenlere sahip olduklarını ve son teknolojileri aktardıklarını ifade ederler. Aslında gerçek sadece şudur; siz eğitim kurumuna değil eğitmenine para vermelisiniz. Gerçekten o eğitim kurumunun almak istediğiniz eğitimle ilişkili olan konuda son derece saygın, size fayda sağlayacak, deneyimli bir eğitmeni varsa bu durumda eğitimden gerekli yararı sağlayabilirsiniz.

Uzmanlaşmak

Yazılımcının kendisini eğitmesi sırasında yaşadığı önemli güçlüklerden biriside uzmanlaşmadır. Yazılım çok geniş bir dünyadır hatta bir evrendir. Bu sebepten yazılımcıların galakside kendilerini kaybetmeleri son derece doğaldır. Dolayısıyla yazılım içerisinde de belirli konularda uzmanlaşmak gerekebilir. Bu artık bir mecburiyet halini almıştır. Söz gelimi .Net Framework cephesinde servis tabanlı çözümlerde, Web veya Windows tabanlı uygulamalarda ya da Mobil cihazlar üzerinde uzmanlaşılabilir. Aslında buradaki uzmanlaşma fikri bir aşçının uzmanlığına benzetilebilir. Sadece Fransız veya Çin mutfağında ortalığı kasıp kavuran bir aşçı kendi istekleri doğrultusunda seçtikleri alanlarda uzmanlaşmıştır denilebilir. Ancak burada kaçınılmaz bir gerçek vardır. Birden fazla mutfakta uzmanlaşmış olan bir açşı diğerlerine göre çok daha fazla kazanacaktır. Wink Aynı prensip yazılımcılar için de geçerlidir.

Yaşananlardan : Çok yakın zamanda başlayan ama bir süre sonra iptal edilmek zorunda kalınan bir projede, .Net tabanlı bir iş akışı geliştirme sisteminin yazılması istenmekteydi. Projenin en ilginç noktası sistemi kullanacak firma yöneticilerinin onay mekanizmasına Blackberry cihazları ile dahil olmak istemeleriydi. Bu noktada Blackberry cihaz üzerinde otomatik bildirimde bulunacak ve onaylama, red etme, geri gönderme gibi fonksiyonellikleri sunacak bir yazılımın olması gerekmekteydi. Dolayısıyla bizim Blackberry cihazlarında geliştirme konusunda bir şeyler öğrenmemiz bekleniyordu. Zaman azdı ve projede analiz ile çözüm tasarım süreçleri bitmek üzereydi. Güvendiğim tek şey geçmiş yazılım tecrübem, programlama disiplinlerine olan hakimiyetim, çözüm tasarımı yeteneğim, analizi iyi kavramış olmam ve öğrenme isteğimdi. Sizlerde zaman içerisinde bu gibi durumlara düşebilirsiniz. Burada kendi kendinizi eğitme ve yetiştirme teknikleriniz ön plana çıkıp öğrenme sürecinizi belirleyecektir. 

Güvenilir Bilgi

Yazılımcının kendi kendisini geliştirmesinde internet tabanlı kaynaklarında yeri büyüktür. Bu alanda sayısız Community ve Blog mevcuttur. Ancak burada güvenilir olan bilgiye ulaşmak gerekmektedir. Bu sebepten dolayı yazılımcılar olarak sizlerin çok daha seçici davranması gerekmektedir. Ne yazık ki en büyük yanlış, yayınlanan teknik içeriklerin denetlenmemesidir. Eğer düzenli olarak yerli siteleri takip ediyorsanız teknik içerikli makale veya günlük girdilerine yabancı sitelerdekine oranla çok daha az sayıda yorum yapıldığını ve geri bildirimde bulunulduğunu görebilirsiniz.  Oysaki pek çok güvenilir yabancı kaynaklı sitede, yayınlanan içerikten daha uzun yorumlar olduğunu ve geri dönüşler bulunduğunu fark edebilirsiniz. Bu da yazının kaliteli olması halinde sizin için çok daha doyurucu bir içerik oluşması anlamına gelmektedir. Nitekim o konu üzerinde farklı kişilerin görüşlerini de almış olursunuz.

Peki güvenilir sitelere nasıl ulaşabilirsiniz? Dikkat edebileceğiniz ilk nokta yazarın künyesi olacaktır. Microsoft içerisinden gelen, RD, MVP gibi ünvanlara sahip olan yabancı yazarların çoğu sizlere tatmin edici içerikler sunacaktır. Özellikle güvenilirliğinden emin olduğunuz kişilerin varsa bloklarını veya feed' lerini yardımıcı bir program aracılığıyla düzenli olarak takip edebilirsiniz. Örneğin benim kullanmakta olduğum FeedReader programını bu anlamda değerlendirebilirsiniz.

Gördüğünüz üzere değerli meslektaşlarım yazılımcıların her daim kendilerini öğrenci olarak görmelerinde yarar vardır. Gerçekten yazılımı bir yaşam biçimi olarak düşündüğünüzde aslında uzun yıllar boyunca sürecek bir Go oyununa dahil olduğunuzu da görebilirsiniz. Go oyununda öğrenci olarak 30 kyu' dan başlayıp ilerlersiniz. Ancak DAN mertebesi alana kadar öğrencisinizdir ve bu seviyeye ulaşmak hayatınızın bir kaç yılına mal olabilir. Dan aldıktan sonra ise ulaşabileceğiniz en yüksek nokta 9ncu Dan' dır. Tabi oyunun sizin yazılım hayatınıza benzerliği açısından önemli olan katkısı şudur; hep kendinizden daha iyi birisi ile oynayarak ve dolayısıyla kendinizi zorlayarak kademe atlayabilirsiniz. Dan'lara geçtikçe siz artık öğretmen olmaya başlarsınız. Bu da aslında çevrenizdeki yazılımcılara yardım edip onların size danışması anlamında düşünülebilir.

Yazının bu son noktasında halen daha nereden başlayacağınızı bilemeyebilir ve kafanızda çelişkiler yaşayabilirsiniz. Öyleyse şunu deneyin. Yazılım alanında gelmek istediğiniz noktaya odaklanın. Odaklandığınız nokta şu andan 3 yıl sonrası olabilir. Görebildiğiniz kadar ilerisi.(Görebildiğiniz kadar çünkü başta da belirttiğimiz üzere teknolojinin hızı neredeyse ışık hızına yakın) Şimdi geriye doğru gelin. Nelere ihtiyacınız olduğunu not etmeye başlayın. Not ettikleriniz bahsettiğiniz hedefe ulaşmanız için gerekenlerdir. Şimdi bu notlarda yazılanları öğrenmek için neler yapmanız gerektiğini düşünün. Gerekli kitaplar, ilgili siteler, blog adresleri, kişiler, kurumlar...Şu anda en azından nelere ihtiyacınız olduğunu tespit ettiniz. Şimdi aradan uygun olanı seçip sıralı olarak devam edebilir ya da bir kaçına birden başlayarak paralel yürüyebilirsiniz. Kolay gelsin. Zorlu bir maratona başladınız...Laughing

1652 Sayfalık İçerik - Tüm Blog Girdilerim

Çarşamba, 24 Şubat 2010 20:30 by bsenyurt

Merhaba Arkadaşlar,

Sabırsızlanan arkadaşlarım yazının en altındaki download linklerine sıçrayabilirler.

Bir yazılımcı sıkıldığında ne yapar? İşte bu günün sorusu...Büyük ihtimalle işlerinden bunalmış veya bazı şeyleri kafaya taktığından içinden çıkılması güç bir psikoloji altına girmiş bir yazılımcının yapacağı şeyler aslında yine teknoloji merkezli olacaktır. Peki ya siz olsanız ne yaparsınız?

  • Belki internet evreninde kafanızı dağıtacak sitelerde gezinirsiniz. Güncel haberler, spor, magazine bültenleri, sosyal ağlar veya chat.
  • Arkadaşlarınız ile oyun oynarsınız ve büyük ihtimalle bu masa üstünde oynayacağınız Satranç ya da Go olmaz. Olsalar bile bilgisayar başında oynanabilenleri olur. Hatta bunun için sosyal ağınıza bir uygulama bile ekleyebilirsiniz. Kuvvetli ihtimalleden birisi PSP gibi oyun konsollarını değerlendireceğinizidir. Tabi şirketinizin içerisinde Turkcell' de olduğu gibi Playstation odası varsa harika.
  • Kitap okuyabilirsiniz ki bu sıkıntınızı daha da arttırabilir çünkü elinizin altındaki kitapların belki de tamamı yazılım ile ilgilidir.
  • Sinemaya gidebilirsiniz ama büyük ihtimalle teknolojinin sınırlarını zorlayan bir filmi seçersiniz. Örneğin Avatar...
  • Bunların haricinde belki MP3 çalarınız ile yürüyeşe çıkabilirsiniz.
  • Ya da kız arkadaşınız veya eşinizle felekten bir gün/gece çalabilirsiniz.

Peki aranızda sıkılınca kod yazanınız var mı? Laughing

Bu gün öylesine çok sıkıldım ki...İçimden pek bir şey yapmak gelmedi. Standart yazılımcı buhranı diyerek ekranıma bakarken bari kod yazayım dedim. Yazacağım kod benim için eğlenceli olsun, sonuçları ise herkes için faydalı olsun istedim. İlk olarak BlogeEngine tabanlı sitemin yönetim paneline girdim ve tüm içeriği dışarıya aktaradım. Artık elimde bloğumda o ana kadar yayınlanmış/yayınlanmamış tüm girdilerin ve bilgilerinin bulunduğu bir XML dosyası vardı. Hımmm... Wink Öyleyse şöyle bir çalışma içerisine girebilirdim; Tüm XML içeriğini alıp anlamlı bir şekilde tek bir HTML içerisinde birleştirmek. Öyle ahım şahım arayüzü olan bir programa da ihtiyacım yoktu. Basit bir Console uygulaması bile işimi görürdü. Çala klavye yazmaya başladım. Tabi yazarken bol bol debug işlemini uygulamam ve içerikte neyin nerede olduğunu anlamam gerekti. Sonunda aşağıdaki kod ortaya çıktı.

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace BlogMLReader
{
    class Program
    {
        static void Main(string[] args)
        {  
             // Önce indirdiğim BlogMl.xml dosyasını bir yükliyeyim
            XElement root = XElement.Load( "..\\..\\BlogML.xml");
            // Sonra içerisinden istediklerimi alayım.
            // Nedir bu istediklerim? Yazının başlığı, url adresi, yayın tarihi/oluşturulma tarihi, içeriği(en önemlisi de bu zaten), tag değerleri           
            var allPosts = from post in root.Elements().Last().Elements()
                           where post.LastAttribute.Value == "True" // Hatta içeriği çekerkende yazdığım ama henüz yayınlamadığım yazıları da alması
                           select new // En güzeli anonymous tip kullanmak. Çünkü her şeyi ele almak istemiyorum. Sadece istediklerimi bir tip içerisinde tutmak niyetindeyim.
                           {
                               Title=post.Elements().First().Value,
                               Url=post.Attribute("post-url").Value,
                               DateCreated = post.Attribute("date-created").Value,
                               Content=post.Elements().ElementAt(1).Value,
                               Tags=from tag in post.Elements().Last().Elements() select tag // Birden fazla tag olduğu için...
                           };

            // İçeriği string olarak ele alacaksam performanslı bir tip lazım. StringBuilder mesela
            StringBuilder builder = new StringBuilder();
           
            builder.Append(String.Format("<b>Döküman Oluşturulma Zamanı {0}</b></br>", DateTime.Now.ToLongDateString()));
            // Birde sayaç belirleyim. En azından ekrana kaç tanesinin yapıldığını yazdırabilirim
            int counter = 1;
            // LINQ sorgusu sonucu elde edilen tüm satırlarda dolaşayım
            foreach (var post in allPosts)
            {
                Console.Write("{0} ",counter.ToString());
                counter++;

                // Şurada bir boşluk bırakayım
                builder.AppendLine("</br>");
                // Yazının başlığını link şeklinde basmalıyım. Basit HTML tag' leri işimi görür
                builder.AppendLine(String.Format("<b><h2><a href=\"http://www.buraksenyurt.com{0}\">{1}</a></h2></b>",post.Url,post.Title));
                // Bir boşluk daha bırakayım
                builder.AppendLine("</br>");
                builder.AppendLine(String.Format("Yayın Tarihi : {0}<br/>", post.DateCreated));
                string newContent=String.Empty;
                // Post' taki image' lara ait resimlerin çekilmesi sırasında image.axd isimli bir adrese yönlendirilme söz konusu. Bu nedenle başlarına duruma göre blog adresini ekleyeyim.
                // Aslında bu image' ları request oluşturup yerel makineye indirip ekleyebilirim ama bunu yapmaya üşeniyorum.
                if(!post.Content.Contains("src=\"image"))
                    newContent = (post.Content.Replace("src=\"/", "src=\"http://www.buraksenyurt.com/"));
                else
                    newContent = (post.Content.Replace("src=\"image", "src=\"http://www.buraksenyurt.com/image"));

                builder.AppendLine(newContent);
                // Sanırım bir boşluk burada iyi gider
                builder.AppendLine("</br>");
               
                #region Write Tags
                // Tag' lerini de yazdırayım da konunun hangi alanlara hitap ettiği anlaşılsın
                builder.Append("<b>Tags : </b>");
                foreach (var tag in post.Tags)
                {
                    builder.Append(String.Format("{0}|",tag.FirstAttribute.Value));
                }
                // Bir boşluk daha iyi gider mi? Gider.
                builder.AppendLine("</br>");

                #endregion
            }
            // Nihayet! Şimdi tüm string' i html uzantılı bir dosyaya yazayım ki tarayıcılarda açabileyim. Hele ki internet bağlantısı da var ise tüm resimler görünür.
            File.WriteAllText("BurakSenyurt_AllPublishedPost.html", builder.ToString(),Encoding.Unicode);
        }
    }
}

Kodu çok fazla açıklama gereği duymuyorum ama basit anlamda XML içeriğini LINQ to XML nimetlerinden yararlanarak ele aldığını ve StringBuilder tipini kullanarak bir HTML dosyası ürettiğini ifade edebilirim. İşte uygulamanın çalışması sonucu ilgili klasör altında oluşan HTML dosyası.

Gördüğünüz gibi HTML dosyası başarılı bir şekilde oluşturuldu. 11 Mb civarında. Wovvv!!! Sealed Tabi kodun bu şekilde bir sonuç ürettiğini gördükten ve HTML içeriğinin tamamının yüklenmesinin tarayıcılara göre çok yavaş olmasından ötürü aklıma başka bir fikir daha geldi. Dedim ki, bu HTML içeriğini ben Word formatında kayıt edersem çok daha yararlı bir ürün ortaya çıkabilir. Böylece herkesin indirip istediği gibi kullanabileceği(kötü niyetli olarak değil tabiki de) bir döküman oluşabilirdi.

Artık bunun için de kod yazayım mı yazmıyayım mı diye düşünürken Firefox ile açtığım HTML içeriği üzerinde Select All yaptım. Aman Allahım. Yapmaz olaydım. Undecided Firefox kitlendi. E haklı tabi. 11 Mb' lık Web sayfası içeriği ona fazla geldi. Peki dedim birde Google Chrome' u deniyeyim. Harika...Başarılı bir şekilde Select All ve Copy işlemi yapıldı. Ama Word içerisine Paste edilebilen hiç bir şey yoktu ortada. Uzun süre bekledim ama zaten sabırsız birisi olduğumdan onu da kapattım. En başta söylemem gerekeni en sonda söyledim...Dedim ki; iki Microsoft ürünü birbirleriyle sorunsuz anlaşır. Internet Explorer 8 ile HTML dosyasını açtım. Dosya açıldı ama resimlerin yüklenmesi Firefox'a hatta Chrome'a göre çok daha yavaştı. Eyvah dedim...Ancak en azından sol alt köşede 1600 küsür resimden kaçıncısını yüklediğini söylüyordu. Buna göre tahmini olarak ne kadar bekleyeceğimi biliyordum. Resimler yüklendikten sonra Select All yaptım. Belki bir kaç on saniye bekledikten sonra tüm içerik seçili haldeydi. Hemen Word 2007 tarafına geçtim ve Paste işlemini uyguladım. Volaaaaa!!! İşlem başarılıydı.Laughing Tabi HTML içeriğini oluştururken Title' lara Heading takısını uygulamanın avantajlarını da hemen gördüm. Nitekim aşağıdaki resimden de görüldüğü üzere Document Map otomatik olarak oluşturulmuştu.

Tabi Word dökümanının boyutu 30 Mb' ı geçmişti. Undecided Neyseki hosting firması DiscountAsp.Net' in sitem için ayırdığı 1 gb' a varan alanı bu boyut için müsaitti. Tabi çok doğal olarak ilk yazılarda yer alan Flash nesneleri bu Word dosyası içerisinde oynamıyor. Ama Title' ların aynı zamanda makale linki olduğunu hatırlatmak isterim. Dolayısıyla internet bağlantınız mevcut ise doğrudan buraksenyurt.com adresine de gidebilirsiniz.

Not : 4 Gb Ram'e sahip çift çekirde intel işlemcili makinemde, Windows 7 işletim sisteminin yönetimi altındaki Word 2007 programı, söz konusu dökümanı yaklaşık olarak 40 saniye civarlarında açabilmekte.

Umarım işinize yarar. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

AllPosts.rar (30 Mb)

Paralel Programlamada Performans, Hız, Verimlilik ve Ölçeklenebilirlik Ölçümleri

Pazartesi, 22 Şubat 2010 10:05 by bsenyurt

Merhaba Arkadaşlar,

Ben Matematik Mühendisliği eğitimi almış bir bireyim. Öğrenim hayatım boyunca en çok yaptığım işlerden birisi, matematiksel teoremlerin bilimsel ispatlarını gerçekleştirmek olmuştur. Hemen hemen mühandisliğin her alanındaki farklı problemlerin modellenmesi ve ispatlarının yapılarak en uygun yol olduklarının gösterilmesi adına pek çok kağıt karalamış ve tüketmişimdir. Zaman zaman neden yaptığımızı anlamadığım ispatlardan tutunda, lastiğine konumuş olan sineğin bisikletin ileriye yönlü ama düz bir rotada olmayan hareketi boyunca çizdiği sarmalımsının denklemini çıkartmaya kadar matematiğin bir o kadar garip ama gizemli evreninde dolaşıp durduğumu hatırlıyorum. Hatta bir gün Matematik Analiz dersinin finalinde karşılaştığım bir soruda ne hikmetse 1=2 sonucuna ulaşmışımdır. Halbuki 1=1' e ulaşmış olmam gerekirdi. Sealed  

Tabi zaman ilerleyip iş para kazanmaya gelince kimsenin teorem ispatları ile uğraşmadığnı acı olarak farketmiştim. İlgi duyduğum yazılım sektörüne gireli uzun yıllar olduğu için matematiksel teorem ispatlarında tam anlamıyla pas tutmuş durumdayım. Yine de zaman zaman yazılım içerisinde matematiği basit haliyle bile görebilmek, en azından bazı konuların ispatında kullanabiliyor olmak sevindirici.

Gelelim bu yazımızın konusuna. Bildiğiniz üzere bir süredir paralel programlama ile ilişkili konuları incelemeye çalışıyor ve öğrenebildiklerimi sizlerle paylaşıyorum. Yine bu vesile ile geçtiğimiz haftalar içerisinde internette dolaşırken gözüme ilişen kısa ve özlü bir yazı ile karşılaştım. Microsoft Paralel programlama takımı tarafından yayınlanan FAQ girdisinde, çeşitli kriterlere göre hangi kodun daha iyi olduğunun ölçümlenebilmesi için hangi kriterlere bakılabileceği özetlenmektedir. Kısaca elimizde aşağıdaki tabloda yer alan kriterler mevcut. Bu kriterlere göre seri ve paralel olarak yazılmış kod algoritmalarının kıyaslanması mümkün. Özellikle yazdığımız paralel program kodlarının normal versiyonlarına göre daha iyi olup olmadıklarının tespit edilmesi noktasında son derece mühim kriterler olduklarını düşünmekteyim.

Kriter

Açıklama

Performance(Performans)

Genel olarak seri ve paralel yazılmış kodların performans ölçümlerinde algoritmanın toplam icra süreleri hesaba katılmaktadır. Çoğunlukla ve pek tabii olarak bir algoritmanın yürütülme süresinin diğerine göre daha düşük olması tercih edilir ki bu iyi bir perfomans anlamına gelmektedir.

SpeedUp(Hızlanma)

Hızlanma değerini hesap etmek için şu formül kullanılır;

SpeedUp = Seri Çalışma Süresi / Paralel Çalışma Süresi

Bu formülün sonucuna göre bir algoritmanın diğerinden kaç kat hızlı olduğu belirlenebilir.

Efficiency(Verimlilik/Etkinlik)

Tabiki yazılan algoritmanın çalıştırıldığı seri veya paralel işleyişin hangisinin tercih edileceği kararını vermede rol oynan kriterlerden birisi de hangisinin daha verimli olduğudur. Verimliliği veya etkinliği hesap etmek içinse aşağıdaki formülden yararlanıldığı görülmektedir.

Efficiency = Hızlanma / İşlemci Çekirdek Sayısı

Scalability(Ölçeklenebilirlik)

Ölçeklenme bilimsel alanda son derece yaygın kullanılan etkili bir terimdir. Şu anki konumuza baktığımızda ise yazılan algoritmanın seri ve paralel denemelerine ait SpeedUp değerlerinin farklı sayıda çekirdek/işlemci için nasıl sonuçlar verdiği ile alakalıdır. İşlemci veya çekirdek sayısının artması ile SpeedUp değerlerinin düşmesi bir başka deyişle daha hızlı sonuçlar elde edilmesi, pozitif ölçeklenmenin ispatı olarak düşünülebilir. Yani işlemci/çekirdek sayısının artması dolayısıyla ortamın büyümesi karşılığında hızlanmanında artması beklenir.

Kişisel Not : Her ne kadar söz konusu yazıda sadece çekirdek sayıları hesaba katılsa da bana göre ram ve işlemci tiplerinin de söz konusu algoritmanın seri veya paralel çalışması durumlarındaki ölçeklenmeyi etkileyeceği ve hesaba katılması gerektiği düşüncesindeyim.

Haydi gelin buradaki ölçüm değerlerini örnek bir kod üzerinden incelemeye çalışalım. Bu amaçla Visual Studio 2010 Ultimate RC ve .Net Framework 4.0 RC üzerinde basit bir Console uygulaması geliştiriyor olacağız. Örneğe ait senaryomuz ise şu şekilde olacaktır.

Bir klasör içerisinde yer alan jpg uzantılı resim dosyalarının boyutlarının arttırılmasını ele alan bir kod parçası geliştireceğiz. Resimlerin boyut arttırım işleminin zaman alan ve yorucu bir işlem olduğu düşünüldüğünde, seri ve paralel kodların ürettiği sonuçları yukarıdaki kriterler eşliğinde değerlendirmeye çalışacağız. Ne yazık ki elimde sadece çift çekirdekli iki makine olduğundan Scalability kriterini bu örnekte sizlere gösteremiyorum Undecided Ancak sizler uygun test ortamlarına sahipseniz, ölçeklenebilirlik kriterini değerlendirebilirsiniz ki değerlendirmenizi tavsiye ederim. İşte Console uygulaması kodlarımız...

using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;

namespace ProofOfConcept
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] files = Directory.GetFiles("..\\..\\Images\\", "*.jpg");

            // Execution süreleri tüm kriterlerde önemlidir. Bu hesaplama için Diagnostics isim alanında yer alan Stopwatch tipinden yararlanılır
            Stopwatch watcher = new Stopwatch();
            watcher.Start();
            SerialExecution(files);
            watcher.Stop();
            // Seri çalışmanın toplam işlem süresi milisaniye cinsinden elde edilir
            float serialElapsed=Convert.ToSingle(watcher.ElapsedMilliseconds);
            
            watcher.Restart();
            ParallelExecution(files);
            watcher.Stop();
            // Paralel çalışmanın toplam işlem süresi milisaniye cinsinden elde edilir
            float parallelElapsed = Convert.ToSingle(watcher.ElapsedMilliseconds);

            // Kriterler hesaplanır
            Console.WriteLine("Serial Performance {0} mili saniye \t Parallel Perfomance {1} mili saniye",serialElapsed,parallelElapsed);
            float SpeedUp = serialElapsed / parallelElapsed;
            Console.WriteLine("SpeedUp {0}",SpeedUp);
            double Efficiency = SpeedUp / Environment.ProcessorCount;
            Console.WriteLine("Efficiency {0} (% {1})", Efficiency,Efficiency*100);
            Console.WriteLine("Scalability bu örneğimizde ne yazıkki test edilemedi");
        }

        // Seri çalıştırma metodumuz
        static void SerialExecution(string[] fileList)
        {
            foreach (string file in fileList)
            {
                Resize(file);
            }
        }

        // Paralel çalıştırma metodumuz
        static void ParallelExecution(string[] fileList)
        {
            // Dosyaları Paralel ForEach döngüsüne göre ele almakta.
            Parallel.ForEach<string>(fileList, s => Resize(s));
        }

        // Resim dosyasını yeniden boyutlandırmak için kullandığımız metod
        static void Resize(string fileName)
        {
            // Önce Image tipi elde edilir
            Image img = Image.FromFile(fileName);
            //Yeni genişlik ve yükseklik değerleri belirlenir. Örnek olarak % 40 artım yapılmıştır
            int newWidth = Convert.ToInt32(img.Width * 1.40);
            int newHeight = Convert.ToInt32(img.Height * 1.40);
            // Yeni boyutlarına göre bir Bitmap nesnesi örneklenir
            Bitmap btmp = new Bitmap(img, new Size(newWidth, newHeight));
        }        
    }
}

Uygulamayı kendi makinemde (Intel Core2Duo, 2.5 Gb Ram), 45 resim(44.8 Mb) üzerinde test ettiğimde aşağıdaki sonuçları elde ettim. Burada seri ve paralel yürütmeler arasındaki farklılıklar kriterler bazında açık bir şekilde ortaya çıkmakta.

Buna göre paralel çalıştırmanın performansı seri olana göre daha yüksektir. Ayrıca paralel çalıştırma, seri olana göre 1,55 kata kadar daha hızlıdır. İlaveten paralel olan çalıştırmanın seri olana göre %77 daha verimli/etkili olduğu sonucuna ulaşılabilir. Tabi bu kodu farklı sayıdaki işlemci veya çekirdek sayısına sahip sistemlerde defalarca test edip bir istatistik çıkartmak ve bunun sonuçlarına bakmak daha doğru olacaktır. İsterseniz bu kod parçasında farklı bir deneyimi tecrübe edebilirsiniz. Örneğin SerialExecution ve ParallelExecution metodlarını arka arkaya 10 kez çalıştırıp sonuçları Excel tablosunda istatistikleştirip gerekli analizleri yapabilir ve hangisini tercih edebileceğinize daha kolay karar verebilirsiniz. En azından ispatı daha güçlü kılarsınız. Wink Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

ProofOfConcept_RC.rar (4,33 mb) [Örnek Visual Studio 2010 Ultimate RC sürümü üzerinde geliştirilmiş ve test edilmiştir]

WF 4.0 - Bookmarks [RC]

Cuma, 19 Şubat 2010 14:04 by bsenyurt

Merhaba Arkadaşlar,

Çalışmakta olduğum yazılım şirketinin çok yakınında kocaman bir alışveriş merkezi bulunmakta. Bazen öğle yemekleri için alışveriş merkezinin tahsis ettiği servisler ile oraya gidiyoruz. Alışveriş merkezi olduğu için tehlikeli bir yer olduğunu da söyleyebiliriz. Sealed Nitekim çok büyük bir yer ve A' dan Z'ye herşey bulunabilmekte. Arkadaşlarım ile sık uğradığım mekanlardan birisi de D&R kitap evi. Çoğunlukla aylık dergilerimi almak için uğramaktayım (Aslında Türkiye' de Amazon gibi bir kitap dağıtım evi olmadığı için çok şanslı olduğumu düşünüyorum. Her halde öyle bir yer açılsa kazancımın çok büyük bir kısmı meslek kitaplarına gider) Geçen gün yine Bilim Teknik, NTV Bilim ve NG dergilerimi almak üzere oradaydım. Sırada beklerken kasada ücretsiz olarak verilen kitap ayraçlarını farkettim. Hep görürdüm ama bu gün biraz daha anlamlı geliyorlardı. Üzelerinde çeşitli reklamlar veya faydalı bilgiler bulunan bu ayraçlar yardımıyla(ki Bookmark diyebilir miyiz acaba? Wink), okuduğumuz kitabın neresinde kaldığımızı kolayca hatırlayabildiğimizi düşünmeye başladım. Derken evde uzun süredir el değdirip kaldığım yerden devam edemediğim kitaplarım aklıma geldi. Hüzünlendim...Tongue out Tesadüfe bakın ki bu kitapları okumak baya uzun sürmüştü. Zamanın neresinde okumaya başladığımı pek hatırlamamakla birlikte, neresinde kaldığımı da hatırlamadığım bir kaç kitap...Tesadüfe bakın ki bu uzun sürecin benzeri Workflow Uygulamalarında da söz konusu olabilmekteydi. Wink

Aslında .Net Framework 3.5 sürümünde Uzun Süreli İşemlerin(Long Running Process) için ExternalDataExchangeService veya WorkflowQueue tiplerinden yararlanılmaktadır. Ne varki Workflow Foundation 4.0 sürümünde, geliştiricilerin kulağına daha hoş gelen Bookmark kavramı ile karşılaşmaktayız. Peki Bookmark nedir? Ne işe yaramaktadır? Nasıl kullanılmaktadır? Konuyu anlamanın belki de en kolay yolu her zaman ki gibi basit bir örnek üzerinden ilerlemekle olacaktır. Bu nedenle Bookmark kavramının tanımlamasını yazımızın sonunda yapmaya çalışacağız.

Bookmark kullanımında önemli olan noktalardan birisi, geçici olarak duraksatılabilecek(Pause) Activity bileşeninin Workflow' un çalışma zamanı içeriğine ulaşabiliyor olmasıdır. Bu nedenle en uygun aktivite bileşenleri, NativeActivity(veya NativeActivity<T>) türevli olanlardır. Bunu ilk gereksinimimiz olarak düşünebiliriz. Aşağıdaki diagramda .Net Framework 4.0 RC sürümü içerisinde yer alan NativeActivity tipleri ve üyeleri görülmektedir.

Şimdi bu türetmeyi kullanarak aşağıdaki kod parçasında görülen aktivite bileşenini geliştirdiğimizi düşünelim. İlgili örneğin bir Workflow Console Application üzerinden geliştirebiliriz.

using System;
using System.Activities;

namespace HelloBookmarks
{

    public sealed class ResizeImageActivity
        : NativeActivity
    {
        protected override bool CanInduceIdle
        {
            get
            {
                return true;
            }
        }

        protected override void Execute(NativeActivityContext context)
        {
            Console.WriteLine("Resize Image bir takım işlemler yapıyor");
            // Bazı işlemler
            // İkinci parametre BookmarkCallback temsilcisi tarafından işaret edilen bir fonksiyondur.
            context.CreateBookmark("ResizeImageBookmark",               
                (nac, b, obj) =>
                {
                    Console.WriteLine("Resume edilen bookmark adı {0}",b.Name);                   
                }
            );
        }
    }
}

Bookmark işlemleri Idle konuma düşebilen Workflow aktivitelerinde işe yarayacak bir teknik olarak düşünülmelidir. Nitekim bir aktivite içerisinde herhangibir zamanda Pause etme ve sonraki bir anda Resume etme söz operasyonları konusudur. Bu sebepten CanIncludeIdle özelliğinin override edilmesi ve geriye true değer döndürmesi söz konusudur. Aksi durumda çalışma zamanında aşağıda görülen InvalidOperationException hata mesajı alınacaktır.

CreateBookmark metodunun ikinci parametresi BookmarkCallback tipinden bir temsilcidir(Delegate). Bu temsilcinin yapısı ise aşağıdaki gibidir.

public delegate void BookmarkCallback(System.Activities.NativeActivityContext context, System.Activities.Bookmark bookmark, object value)

Buna göre örneğimizde yer alan isimsiz metodun(Anonymous Method) ilk parametresi ile Activity' nin çalışma zamanındaki çevresel içeriğine, ikinci parametre ilede Bookmark örneğine erişilebilir. Bu temsilci aslında bir geri bildirim metodunu(Callback Method) işaret etmektedir. Bir başka deyişle, Idle konumda kalan Activity örneğinin tekrar Resume edilmesi halinde devreye girecek olan metod olarak düşünülebilir. Dolayısıyla geri bildirim metodu içerisinde CreateBookmark tarafında saklanan bazı varlıkların tekrardan yüklenmesi, hazırlanması gibi operasyonlar ele alınabilir. CreateBookmark metodunun aslında 8 aşırı yüklenmiş(Overload) versiyonu bulunmaktadır. Diğer versiyonlar göz önüne alındığında dikkat çeken parametrelerden birisi BookmarkOptions Enum sabitidir. Bu enum sabiti MultipleResume, NonBlocking ve None değerlerinden birisini almaktadır. Varsayılan değer None' dır. MultipleResume olması halinde bir den fazla Resume işlemi yapılabileceği belirtilir. NonBlocking değerine göre ilgili aktivite bileşeni Resume edilmemiş olsa dahi WF' in çalışacağını belirtilir. Nitekim normal şartlar altında bir aktivite içerisinde oluşturulan Bookmark' ların tamamı Resume edilmediği sürece WF' in tamamlanması söz konusu değildir. Dilerseniz MultipleResume ve NonBlocking değerlerini bir arada kullanabilirsiniz. Gelelim aktivitenin nasıl kullanılacağına. Örneğimizdeki amacımız sadece Bookmark kullanımını görmek olduğundan aşağıdaki şekilde görülen Workflow Activity içeriğini değerlendirebiliriz.

Bookmark kullanımı yazımızın başında da belirttiğimiz üzere uzun süreli işlemler(Long Running Process) için anlamlıdır. Bu sebepten WorkflowApplication tipinin kullanılması gerekmektedir. Workflow Console Application tipinden olan uygulamamızda, çalışma zamanındaki Idle durumları irdelememiz aslında son derece kolaydır. Console.ReadLine metodu burada çok işe yarayacaktır. Wink İşte kod içeriğimiz;

using System;
using System.Activities;
using System.Threading;

namespace HelloBookmarks
{

    class Program
    {
        static void Main(string[] args)
        {
            AutoResetEvent rE = new AutoResetEvent(false);
           
            // Workflow örneği oluşturlur
            Workflow1 wf1 = new Workflow1();
            // Workflow Application örneği oluşturulur
            WorkflowApplication wfApp = new WorkflowApplication(wf1);
            // Workflow' un tamamlanması sonrası devreye girecek Completed olay metodu
            wfApp.Completed = (e) => { rE.Set(); }; // işlemlerin bittiğine dair bilgilendirme için AutoResetEvent örneğinin Set metodu çağırılır.
            // Workflow çalışma zamanı başlatılır dolayısıyla Workflow1 örneği yürütülür
            wfApp.Run();           
            Console.WriteLine("Bir süre bekleyin...");
            Console.ReadLine(); // Bu noktada Workflow1 örneğinin Idle konuma geçmesi söz konusudur.
           
            /* Kullanıcı devam etmek istediğinde Bookmark' lanan Workflow1 örneğine tekrardan hayata geçirilir. ResumeBookmark metodunun ilk parametresi dikkat edileceği üzere ResizeImageActivity içerisinde kullanılan Bookmark adıdır. Bu adın aslında aktivite bileşeni içerisinden çalışma zamanı ortamına verilmesi(örneğin bir OutArgument) ile faydalı olabilir. İkinci parametre ise hangi Workflow örneğinin Resume edileceğidir. Buna göre Workflow1 içerisinde ResizeImageBookmark isimli Bookmark' ın yer aldığı aktivite bileşeninin Resume edilmesi söz konusudur. */
            BookmarkResumptionResult result = wfApp.ResumeBookmark("ResizeImageBookmark", wf1);
            // ResumeBookmark metodunun sonucu olan Enum sabitinin değerine göre bir işlem yapılabilir
            switch (result)
            {
                case BookmarkResumptionResult.NotFound:
                    Console.WriteLine("Not Found");
                    break;
                case BookmarkResumptionResult.NotReady:
                    Console.WriteLine("Not Ready");
                    break;
                case BookmarkResumptionResult.Success:
                    Console.WriteLine("Success");
                    break;
                default:
                    break;
            }
           
            // Eğer Workflow Application' ın beklediği çalışan örnekler var ise bunların tamamlanması beklenir
            rE.WaitOne();
        }
    }
}

Aslında örnek kodumuz Workflow1 tipinden bir nesne örneğini çalıştırmakta ve yaşamı içerisinde kullanıcından belirli süreliğine tuşa basmasını beklemektedir. Tuşa basmayı beklediği sırada ise Idle olabilen bileşenlerin bu konuma geçmesi söz konusudur. ResumeBookmark çağrısından sonra ise Bookmark ile Pause konumda duran aktivitenin ilgili geri bildirim metodunun çağırılması ve dolayısıyla yürütülmeye devam edilmesi sağlanır. İşte örnek program kodumuzun çalışma zamanı çıktısı.

Bu arada çalışma zamanında aktif olan Bookmark listesini de WorkflowApplication nesne örneğine ait GetBookmarks metodu üzerinden alabileceğinizi belirtmek isterim. Aşağıdaki kod parçasında bu durum örneklenmektedir.

using System;
using System.Activities;
using System.Threading;
using System.Activities.Hosting;

namespace HelloBookmarks
{
    class Program
    {
        static void Main(string[] args)
        {
            AutoResetEvent rE = new AutoResetEvent(false);                       
            Workflow1 wf1 = new Workflow1();
            WorkflowApplication wfApp = new WorkflowApplication(wf1);
            wfApp.Completed = (e) => { rE.Set(); }; // işlemlerin bittiğine dair bilgilendirme için AutoResetEvent örneğinin Set metodu çağırılır.
            wfApp.Run();           
            Console.WriteLine("Bir süre bekleyin...");
            Console.ReadLine();
            foreach (BookmarkInfo bm in wfApp.GetBookmarks())
            {
                Console.WriteLine(bm.BookmarkName);
            }           
...

Şimdi örneğimizi biraz daha ilginç bir hale getirelim. Öncelikli olarak aşağıdaki kod içeriğine sahip Custom Activity sınıfını oluşturarak projemize ilave edelim.

using System;
using System.Activities;

namespace HelloBookmarks
{

    public sealed class SendImageActivity
        : NativeActivity
    {       
        protected override bool CanInduceIdle
        {
            get
            {
                return true;
            }
        }

        protected override void Execute(NativeActivityContext context)
        {
            Console.WriteLine("Send Image bir takım işlemler yapıyor");
            context.CreateBookmark("SendImageBookmark",               
                (nac, b, obj) =>
                {
                    Console.WriteLine("Resume edilen bookmark adı {0}",b.Name);                   
                }
            );
        }
    }
}

ResizeImageActivity tipinin tıpkısının aynısı olan bu bileşeni de ele alarak Workflow1 içeriğini aşağıdaki şekilde görüldüğü gibi değiştirelim.

Bu sefer aynı anda birden fazla aktivitenin çalıştırılmasına izin veren Parallel bileşeninden yararlanmaktayız. İncelemek istediğimiz nokta ise şu; her iki aktivite de Execute metodları içerisinde birer Bookmark oluşturmaktadır. Buna göre program kodumuzda birden fazla Bookmark' ın nasıl ele alınacağına bakmak istiyoruz. Söz konusu vakayı analiz etmek için, Main metoduna ait kod içeriğini aşağıdaki gibi değiştirmemiz yeterli olacaktır.

using System;
using System.Activities;
using System.Threading;
using System.Activities.Hosting;

namespace HelloBookmarks
{
    class Program
    {
        static void Main(string[] args)
        {
            AutoResetEvent rE = new AutoResetEvent(false);           
            Workflow1 wf1 = new Workflow1();
            WorkflowApplication wfApp = new WorkflowApplication(wf1);
            wfApp.Completed = (e) => { rE.Set(); };
            wfApp.Run();           
            Console.WriteLine("Bir süre bekleyin...");
            Console.ReadLine();
            Console.WriteLine("***Etkin Bookmark Listesi***");
            foreach (BookmarkInfo bm in wfApp.GetBookmarks())
            {
                Console.WriteLine("Bookmark Name:{0}, Owner:{1}",bm.BookmarkName,bm.OwnerDisplayName.ToString());
            }
            Console.WriteLine();
           
            BookmarkResumptionResult result1 = wfApp.ResumeBookmark("ResizeImageBookmark", wf1);
            BookmarkResumptionResult result2 = wfApp.ResumeBookmark("SendImageBookmark", wf1);

            Console.WriteLine("ResizeImageBookmark için Resume Result : {0}",result1.ToString());
            Console.WriteLine("SendImageBookmark için Resume Result : {0}", result2.ToString());

            rE.WaitOne();
            Console.ReadLine();
        }
    }
}

Ve işte çalışma zamanı sonuçları;

Çıktımıza göre her iki akitivite bileşeni, eş zamanlı olarak Execute metodlarını icra etmiş ve birer Bookmark oluşturmuştur. Sonrasında kullanıcının tuşa basması ile devam eden süreçte ilk olarak yüklü olan Bookmark' lar listelenmiş ve ardından ResumeBookmark çağrıları nedeniyle Pause edilmiş olan aktivitelerin geri bildirim operasyonları devreye girmiştir. Her iki Bookmark' ında Resume edilmesinin sonucu olarak Workflow1 örneğinin işlemlerini tamamladığı anlaşılmaktadır. Program kodu da buna göre sonlanır.

Görüldüğü gibi bir aktivitenin Bookmark' lanması aslında isimlendirilmiş duraksama noktalarına(Named Pause Points) sahip olması anlamına gelmektedir. Öyleki, ResumeBookmark metodu sayesinde Pause edilen noktadan tekrar yürütülmeleri sağlanabilir. Böylece geldik bir yazımızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

HelloBookmarks.rar (54,52 kb) [Örnek Visual Studio 2010 Ultimate RC sürümü üzerinde geliştirilmiş ve test edilmiştir]

WCF WebHttp Services - JSON Formatlı Response Üretmek

Cuma, 19 Şubat 2010 07:50 by bsenyurt

Merhaba Arkadaşlar,

Yandaki Logo size neyi çağırıştırıyor? Aslında bakarsanız çok meşhur olan hafif siklette bir veri değiş tokuş formatının logosunu ifade etmekte. JSON(JavaScript Object Notation). Hatırlayacağınız üzere bir süredir WCF Eco System içerisinde yer alan WCF WebHttp Service alt yapısını incelemeye çalışıyoruz. WCF WebHttp Service' leri eğer istemci tarafından aksi belirtilmezse varsayılan olarak XML formatında çıktı üretmektedir. Ancak istenirse JSON(JavaScript Object Notation) formatında çıktı üretmeside sağlanabilir. Söz konusu çıktı üretim işlemi iki yolla gerçekleştirilebilir. Bilinçli olarak(Excplicitly) veya otomatik olarak. Bu yazımızda söz konusu yolları inceleyerek JSON formatında çıktıları nasıl verebileceğimizi basit bir örnek üzerinden görmeye çalışıyor olacağız. Örnek uygulamamızı bu kez Visual Studio 2010 Ultimate RC ortamı üzerinde geliştirdiğimizi belirtelim. Dolayısıyla ilerleyen sürümde bazı farklılıklar olabilir. Lesson3 isimli WCF REST Service Application uygulamamız içerisinde yer alan servis sınıfı içeriğimiz çok basit olarak aşağıdaki kod parçasından oluşmaktadır.

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace Lesson3
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class PersonalityService
    {
        [WebGet(UriTemplate = "AllPersons")]
        public List<Person> GetAllPersons()
        {
            return new List<Person>()
            {
                new Person() { Id = 1, Name = "Burak Selim Şenyurt",Birth=new DateTime(1976,12,1) } ,
                new Person() { Id = 2, Name = "Bill Amca",Birth=new DateTime(1975,4,5) } ,
                new Person() { Id = 3, Name = "Luka Ton-i",Birth=new DateTime(1980,3,4) }
            };
        }
    }

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Birth { get; set; }
    }
}

Servisimizde yer alan GetAllPersons isimli operasyon istemci tarafına Person tipinden bir liste içeriği döndürmektedir. Söz konusu operasyon HTTP protokolünün GET metoduna ait talepleri kabul etmektedir. Varsayılan olarak URL üzerinden yapacağımız AllPersons çağrısının sonucu aşağıdaki gibi olacaktır.

Ancak şimdiki hedefimiz bu XML çıktısı yerine JSON çıktısını vermektir. Bunu iki yol ile gerçekleştirebileceğimizden bahsetmiştik. Öncelikle otomatik JSON çıkıtısı üretiminin nasıl gerçekleştirilebileceğine bakalım. Bu amaçla sunucu tarafındaki web.config dosyası içerisinde yer alan webHttpEndpoint içerisindeki standardEndpoint elementinin automaticFormatSelectionEnabled niteliğinin true değere sahip olması yeterlidir. Aynen aşağıda görüldüğü gibi.

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>

Peki bu otomatikliğin anlamı nedir? Undecided Nitekim herhangibir yerde JSON çıktısı vereceğimizi belirtmedik. Dolayısıyla birisinin bunu talep ediyor olması gerekmekte. Tahmin edeceğiniz üzere burada sorumluluk istemci tarafına ait. Bir başka deyişle istemci uygulama talebini gönderirken JSON formatında bir içerik istediğini servis tarafına bildirmelidir. Dolayısıyla örneğimize aşağıdaki kodları içeren istemci uygulamayı yazarak devam etmeliyiz.

Not : İstemci uygulama açısından önem arz eden konulardan biriside, HttpClient tipinin kullanımı için gerekli olan WCF REST Starter Kit Preview 2 assmebly' ları ile ReadAsJsonDataContract genişletme metodunun(Extension Methods) kullanımı için gerekli olan System.ServiceModel.Web ve System.Runtime.Serialization assembly' larını referans etmesidir.

Buna göre istemci tarafının kodlarını aşağıdaki şekilde geliştirebiliriz.

using System;
using Microsoft.Http;

namespace ClientApp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (HttpClient client = new HttpClient("http://localhost:2360/"))
            {
                HttpRequestMessage request = new HttpRequestMessage("GET", "AllPersons");               
                request.Headers.Accept.AddString("application/json");
                HttpResponseMessage response = client.Send(request);
                response.EnsureStatusIsSuccessful();
                HttpContent content=response.Content;
                Console.WriteLine(content.ReadAsString());
            }
        }
    }
}

Bu kod parçasında en çok dikkat edilmesi gereken nokta talep ile ilişkili Header kısmına eklenen application/json bilgisidir. Bu durumda HTTP Get metoduna göre yapılan servis çağrısı çıktısının JSON formatında olması istenmektedir. Servis tarafında da gelen isteğe göre bir çıktı üretildiğinden, WCF çalışma zamanı operasyon çıktısını JSON formatına dönüştürecektir. Kodun çalışması sonrasında aşağıdaki ekran çıktısı ile karşılaştığımızı görürüz.

Dikkat edileceği üzere JSON formatında bir çıktı elde edilmiştir.

İstemci tarafına gelen bu çıktının Person tipini içeren bir koleksiyon şeklinde ele alınması istediğimizdeyse HttpContent tipi üzerinden System.Runtime.Serialization.Json isim alanında yer alan ReadAsJsonDataContract genişletme metodunu çağırabiliriz. Tabi burada istemci tarafında Person tipininde bir örneğinin yer aldığını varsayıyoruz ki bunu bildiğiniz üzere WCF REST Starter Kit Preview 2 ile gelen Paste XML As Types seçeneği ile oluşturabiliriz. Eğer hatırlamıyorsanız biraz araştırmaya ne dersiniz? Wink İşte istemci tarafındaki yeni kod içeriğimiz.

using System;
using System.Collections.Generic;
using System.Runtime.Serialization.Json;
using Microsoft.Http;

namespace ClientApp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (HttpClient client = new HttpClient("http://localhost:2360/"))
            {
                HttpRequestMessage request = new HttpRequestMessage("GET", "AllPersons");               
                request.Headers.Accept.AddString("application/json");
                HttpResponseMessage response = client.Send(request);
                response.EnsureStatusIsSuccessful();
                HttpContent content=response.Content;
                //Console.WriteLine(content.ReadAsString());
            
                List<Person> personList=response.Content.ReadAsJsonDataContract<List<Person>>();

                foreach (Person person in personList)
                {
                    Console.WriteLine("{0} {1} {2}",person.Id,person.Name,person.Birth.ToString());
                }
            }
        }
    }
}

Bu durumda çalışma zamanında aşağıdaki sonucu elde ederiz.

Gelelim bilinçli olarak çıktı formatının nasıl belirleneceğine. Öncelikli olarak neden bilinçli bir şekilde format çıktısını söylememiz gerektiğini kavramamızda yarar olduğu kanısındayım. İstemci tarafının her zaman HTTP talebinin Header kısmına müdahale etmesi söz konusu olamayabilir. Böyle bir durumda istemcinin JSON formatında talepte bulunabilmesi de mümkün değildir. Dolayısıyla bu tip bir vakada JSON formatında çıktı verileceğinin bilinçli olarak bildirilmesi gerekmektedir. Peki ya nerede ve nasıl? Cevap: Servis tarafındaki ilgili operasyon içerisinde ve bir parça kod yardımıyla Wink İşte GetAllPersons isimli servis operasyonumuzun bilinçli olarak JSON formatında çıktı veren yeni versiyonu.

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace Lesson3
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class PersonalityService
    {
        [WebGet(UriTemplate = "AllPersons?whichFormat={format}")]
        public List<Person> GetAllPersons(string format)
        {
            if (format.ToLower().Equals("json"))
            {
                WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;
            }
            return new List<Person>()
            {
                new Person() { Id = 1, Name = "Burak Selim Şenyurt",Birth=new DateTime(1976,12,1) } ,
                new Person() { Id = 2, Name = "Bill Amca",Birth=new DateTime(1975,4,5) } ,
                new Person() { Id = 3, Name = "Luka Ton-i",Birth=new DateTime(1980,3,4) }
            };
        }
    }

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public DateTime Birth { get; set; }
    }
}

İlk dikkat edilmesi gereken nokta, WebGet niteliğinde belirtilen format isimli parametre ile istemciden hangi formatta çıktı almak istendiğinin sorulmasıdır. Eğer json kelimesi yazılmışsa WebOperationContext üzerinden güncel çalışma zamanı içeriğine geçilerek cevap formatının JSON olacağı belirtilir ki buda dikkat edilmesi gereken ikinci noktadır. Tahmin edileceği üzere json dışında bir kelime girildiği takdirde varsayılan XML çıktısının üretilmesi söz konusu olacaktır. Servis operasyonumuzun bu son haline göre Internet Explorer üzerinden http://localhost:2360/AllPersons?whichFormat=json şeklinde bir talepte bulunursak, içeriği kaydetmemiz için bir iletişim penceresi ile karşılaşırız. İçeriği kaydettikten sonra Notepad programı ile açacak olursa aşağıdaki içeriğin üretildiğini görebiliriz.

ki buda tam anlamıyla JSON çıktısıdır. Smile Çıktının JSON veya XML harici formatlarda olması da söz konusudur aslında. Bu formatların nasıl ele alınacağını ise ilerleyen yazılarımızda değerlendirmeye çalışıyor olacağız. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Lesson3_RC.rar (173,29 kb) [Örnek Visual Studio 2010 Ultimate Beta 2 Sürümünde geliştirilmiş ancak RC sürümü üzerinde de test edilmiştir]