Microsoft’un Distributed Cache Çözümü : Velocity

Microsoft’un Distributed Cache Çözümü : Velocity

Microsoft’un “Velocity” kod adıyla duyurduğu distributed cache sağlayan alt yapısı ile veri kaynağına gereksiz ve maliyetli çağrılar yapmak yerine dağıtık ortamlarda da caching yapabiliyor olacağız.

Günümüzde kurumsal iş uygulamalarında caching yapmak neredeyse bir zorunluluk halini almıştır. Bir çok alt yapı tasarımında veri kaynağı katmanına (yani database sunucusu) erişmeden önce arada bir cache katmanı yer alır, erişilmeye çalışılan verinin cache’de bulunup bulunmadığına bakılır ve ardından gerçek veri kaynağına erişilir. Cachelenmesi gereken verinin niteliğine göre cache yapısının önemi artmaktadır. Örneğin sadece veri kaynağından alınıp okunan ve ön yüz katmanına geri geçilen bir veriden ziyade farklı veri kaynaklarından aldığı veriyi önce işleyen, iş kurallarından geçiren ve ardından ön yüz katmanına dönen bir yapıda cache’in önemi çok kritik olmaktadır.

Yoğun kurumsal iş uygulamalarında bir web sitesini sunan ya da bir web uygulama sunucusu rolünde çalışan bir sunucu her zaman yeterli olmamaktadır. Ve bu durumda Load Balancing çözümlerine gidilmelidir. En basit haliyle bir web uygulamasını sunan web sunucusun yanına aynı görevi üstlenen ikinci bir web sunucu konması ve ikisinin gelen yüke göre isteklere cevap verme senaryosudur.

Load Balancing ile çalışan iki uygulama sunucunun gösterimi.

Yukarıdaki şekilde de gözüktüğü gibi böyle bir senaryoda caching işlevi yapılırken iki uygulama sunucusunun ortak olarak paylaşacağı bir çözüme gerek vardır. Zira örneğin birinci sunucu üzerinde ASP.NET alt yapısı tarafından sağlanan caching nesne modeli ya da static olarak tanımlamış bir yerde veri saklanıyor olsaydı, ikinci sunucu aynı veriye erişemeyecekti. Aynı şey ikinci sunucunun cachelediği verilere birinci sunucunun da erişememesi şeklinde olacaktır.

Böyle bir senaryoda eğer cachelenecek verinin niteliği izin veriyorsa her uygulama sunucu üzerinde bir cache alanı kalmasına izin verilebilir ve bu şekilde standart yöntemler ile çalışılır. Ancak her zaman cachede saklanacak veri bu nitelikte değildir. Örneğin aynı istemciden gelen isteğe ilk adımda birinci sunucu cevap verdi ve cache alanına o istemcinin isteği sonucunda bazı veriler eklendi. Sonraki isteklerde aynı istemciden gelen isteğin aynı sunucu üzerinde çalışacağı garantisi yoktur. Bu durumda distributed caching yapmak gereklidir.

Load Balancing donanım ya da yazılımlarında kullanıcı oturumlarının sürekli aynı sunucu üzerine yönlendirilmesi şekliden bir ayar bulunmaktadır. Ancak bu oturum mantığında çalışan bir web sitesinde işe yarar. SingleCall çalışan bir uygulama sunucusunda işe yaramayacaktır. Senaryomuzun aldığı son hale göre ;

1.       Uygulama sunucularından birisinin cache sunucusu olarak belirlenebilir.

2.       Ayrı bir cache sunucusu eklenmesi uygun olabilir.

3.       Yada her uygulama sunucusu üzerinde cache alanı olması ancak birisinde yapılan güncellemelerin diğer uygulama sunuculara da yansıması sağlanabilir.

Yukarıda yazdığım çözümler kurduğumuz basit senaryo için yeterlidir. Velocity henüz RTM sürümüne ulaşmadı, RTM olduğunda tüm distributed caching senaryolarına en yüksek performansı sunacağı geliştirenler tarafından söylenmektedir.

Yukarıdaki senaryolardan ayrı bir cache sunucusu belirlenmesi ve tüm uygulama sunucularının bu cache sunucusunu kullanması senaryosunu bu makalemde çözüme kavuşturmaya çalışacağım.

Bu durumda uygulama sunucuları cache sunucusu için birer istemci rolünde çalışmaktadırlar. Bir uygulama sunucusunu cache sunucusu ile birlikte çalışır hale getirmeden önce Velocity’nin bileşenlerini tanıyalım. Velocity ile bir cache sunucusunu nasıl yapılandırıp ayağa kaldıracağımızı inceleyelim.

Velocity Bileşenleri

Velocity sunucusu aşağıdaki şemada gözüktüğü bir Windows servisi olarak çalışabilmektedir. Aynı zamanda birden fazla cache sunucusu da birlikte çalışabilmektedir. Birden fazla cache sunucusu olduğunda uygulanacak yapılandırma ve seçilecek topoloji önem arz etmektedir. Bu makale üzerine oluşacak ilgi üzerine başka bir makalede birden fazla cache host yani cache sunucusu ile bir cache cluster oluşturulmasını inceliyor olabiliriz.

Velocity -fiziksel olarak ayrılmış- bileşenleri

Cache Host: Velocity’nin servisidir, bir Windows servisi olarak çalışabilir. Cache Host bu makale yazıldığı sırada henüz ilk CTP sürümü üç gün önce yayınlanmış olan Velocity’nin bu sürümünde bir sunucu üzerinde sadece bir tane cache host çalışmaktadır.

Cache Cluster: Birden fazla cache hostun veriyi saklamak ve dağıtmak üzere birlikte çalışmasına cache cluster denilir. Tüm cache cluster, cluster içinde yer alan cache hostlardan bazıları yönetirler. Bu görevi üstlenen cache clusterlarına quorum adı verilir. Bu cache host’ların esas görevi tüm clusterin görevini devam ettirebilmesini sağlamak ve verinin cluster içinde yer alan cache hostlar arasında güncel kalmasını ve değişen topolojiye göre routing tableların güncellenmesidir.

ClusterConfig.xml : Bunların yapılandırılması ve kullanılması yine ClusterConfiguration dosyası ile yapılır.

Cache Administration Tool: Tüm cache clusteri yönetmek için bu araç kullanılabilir. Kurulum gerçekleştirildiğinde masaüsütnde bir kısayol oluşturulacaktır. Ancak standart kurulumda C:\Program Files\Microsoft Distributed Cache\V1.0\AdminTool.exe konumuna yüklenecektir. Aynı cluster için yer alan cache hostlar üzerindeki cache nesnelerini, onlara yapılan istekleri, cache regionlarını listeler. start cluster komutu ile tüm clusterdaki cache hostları çalıştırabilir, stop cluster ile durdurabilirsiniz.

Velocity Distributed Cache hizmetinin kurulması.

Velocity kurulumunu indirip çalıştırdıktan sonra kurulum sırasında Configuration konumu için aşağıdaki ekran görüntüsüne gözüken pencere açılacaktır. Cluster Configuration Share olarak girilen değeri yukarıdaki grafikte gözüktüğü şekilde birden fazla cache server olacak şekilde kullanmak isterseniz bir network konumu girebilirsiniz. Ben tek  cache host çalıştıracağım bu yapılandırma için disk üzerinde bir path seçtim. (C:\Users\CengizHan\Documents\VelocityCacheHost)

İlk Uygulama  - Distributed Cache Servisine veri yazmak ve okumak.

Öncelikle kurulduğunda otomatik olarak başlatılmayan servisi çalıştırmalıyız. Bunun için computer managementden servisi çalıştırmamız gerekir.

Yukarıdaki resimde gözüktüğü gibi cache host üzerindeki ilgili servisin adı Microsoft project code named “Velocity” dir.

Bunun yerine administration tool aracılığı ile de servisi başlatabiliriz.

Start cluster komutu ile cache cluster içinde yer alan tüm cache hostlar üzerinde ilgili servisi çalıştırmış oluruz. (Şimdiki örneğimizde tek cache host, tek bilgisayar bulunuyor.)

Cache sunucusuna veri yazma ve okumanın en temel fonksiyonlarını görmek adına bir windows forms application projesi açalım ve aşağıdaki resimde gözüken assembly dosyalarını referans olarak ekleyelim.

C:\Program Files\Microsoft Distributed Cache\V1.0 konumunda yer alan CacheBaseLibrary.dll, ClientLibrary.dll, FabricCommon.dll, CASBase.dll ve CASClient.dll dosyaları referans olarak eklenmelidir.

Ardından projemize bir app.config dosyası ekleyelim. App.config içeriğini aşağıdaki şekilde oluşturalım.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="dcacheClient" type="System.Configuration.IgnoreSectionHandler" allowLocation="true" allowDefinition="Everywhere"/>
    <section name="fabric" type="System.Fabric.Common.ConfigFile, FabricCommon" allowLocation="true" allowDefinition="Everywhere"/>
  </configSections>
  <dcacheClient deployment="simple" localCache="false">
    <hosts>
      <host name="CHAN" cachePort="22233" cacheHostName="DistributedCacheService"/>    </hosts>
  </dcacheClient>
  <fabric>
    <section name="logging" path="">
      <collection name="sinks" collectionType="list">
        <customType className="System.Fabric.Common.EventLogger,FabricCommon" sinkName="System.Fabric.Common.FileEventSink,FabricCommon" sinkParam="CacheClientLog" defaultLevel="1"/>
</collection>
    </section>
  </fabric>
</configuration>

Yukarıdaki yapılandırma dosyasında kalın olarak vurgulanmış olan bölüm bağlanılacak olan cache hostun bilgilerini içerir. Cache host yapılandırma dosyasında verilmiş olan cacheHostName, cachePort ve bağlanılacak cache host’un çalıştığı bilgisayarın adıdır.

Fabric elementi altında verilmiş olan loglama seçenekleri loglama işlemlerini belirler. Loglama için eventloga yazma gibi farklı logger sınıflarıda mevcuttur.Bu örnekte sadece FileEventSink kullanılarak dosyaya loglama yapılmaktadır.

Ayrıca burada verilmiş olan CacheClientLog değeri logların hangi isimdeki dosyaya yazılacağını belirler. Burada uygulama ile aynı klasörde CacheClientLog.log dosyası oluşturulacağı belirlenmiştir.

Örneğin defaultLevel olarak belirlenmiş olan loglama seviyesinde daha az detaylı loglama yaparken. Verbose değerine karşılık gelen 16 değeri ile çok daha detaylı loglama yapmaktadır.

Örneğin cache hosta erişilemediği (bilinçli olarak bilgisayar adını yanlış yazarak elde ettim bu hatayı) durumda aşağıdaki hata logları defaultLevel=1 iken elde edilmiştir.

DeadServerCallback Called, Server URI: net.tcp://CENGIZHANPCasdf:22233/DistributedCacheService,ThinClientCache,Error,2008-6-13 00:30:04.109

DeadServerCallback: Matches My Server, Cleaning Pending Requests,ThinClientCache,Error,2008-6-13 00:30:04.109

ExecuteAPI: Response is Null, msgId = 1,CacheAPI,Error,2008-6-13 00:30:04.115

defaultLevel değerini aşağıdaki gözüktüğü gibi 16 yaparak deneyelim.

        <customType className="System.Fabric.Common.EventLogger,FabricCommon" sinkName="System.Fabric.

Common.FileEventSink,FabricCommon" sinkParam="CacheClientLog" defaultLevel="16"/>

Bu durumda aşağıdaki log dosyası oluşmaktadır.

GetCache: CacheFactory not initialized...Initializing,CacheFactory,Verbose,2008-6-13 00:31:40.342

InitCacheFactory: Initializing Cache Factory,CacheFactory,Verbose,2008-6-13 00:31:40.346

InitCacheFactory: Instantiated Configuration Manager,CacheFactory,Verbose,2008-6-13 00:31:40.361

InitCacheFactory: Deployment Mode Read as ,CacheFactory,Verbose,2008-6-13 00:31:40.361

InitCacheFactory: Instantiated Cache List,CacheFactory,Verbose,2008-6-13 00:31:40.361

InitCacheFactory: CacheFactory Initialization Completed,CacheFactory,Verbose,2008-6-13 00:31:40.396

GetCache: Creating the Named Cache 'default',CacheFactory,Verbose,2008-6-13 00:31:40.397

GenericCache: Constructing Cache: default,CacheAPI,Verbose,2008-6-13 00:31:40.398

GenericCache: Instantiating Hashtable First Time,CacheAPI,Verbose,2008-6-13 00:31:40.398

Initializing First Time,ThinClientCache,Verbose,2008-6-13 00:31:40.400

ExecuteAPI: Begin: RequestId = 1, ReqType = PUT, CacheName = default, RegionName = , Key = uye,CacheAPI,Verbose,2008-6-13 00:31:40.490

SendMsgAndWait: Begin: msgId = 1,ThinClientCache,Verbose,2008-6-13 00:31:40.492

SendMsgAndWait: Serializing Object: msgId = 1,ThinClientCache,Verbose,2008-6-13 00:31:40.492

PrepareWait: Preparing For Wait, msgId = 1,CacheAPI,Verbose,2008-6-13 00:31:40.494

PrepareWait: Populating Hashtable, msgId = 1,CacheAPI,Verbose,2008-6-13 00:31:40.495

SendMsgAndWait: Sending Msg to Server: msgId = 1,ThinClientCache,Information,2008-6-13 00:31:40.499

DeadServerCallback Called, Server URI: net.tcp://CENGIZHANPCasdf:22233/DistributedCacheService,ThinClientCache,Error,2008-6-13 00:31:43.090

DeadServerCallback: Matches My Server, Cleaning Pending Requests,ThinClientCache,Error,2008-6-13 00:31:43.090

ExecuteAPI: Response is Null, msgId = 1,CacheAPI,Error,2008-6-13 00:31:43.095

defaultLevel değerine verebileceğiniz değerler kümesini System.Diagnostics.TraceEventType enumaration’a bakarak görebilirsiniz.

Veri yazmak ve okumak

Veri yazmak ve okumak için artık nesne modeline bakabiliriz. Bunun için aşağıdaki şekilde bir form oluşturup, cache yaz butonu ile veri yazmayı, ve cache oku ile veriyi okumayı deneyeceğiz.

Veri olarak basitçe string bir ifade yazmak yerine bir nesne oluşturup onu yazıp okumayı deneyelim.

[Serializable]

    public class Uye {

        public Uye(string adSoyad) {

            this.AdSoyad = adSoyad;

        }

        public string AdSoyad { get; set; }

    }

Velocity ile cacheleyeceğiniz nesnelerin serializable olarak işaretlenmiş olması zorunludur. Bu yüzden oluşturduğumuz sınıfın üzerinde serializable attribute’unu ekliyoruz.

Daha sonra butonlara tıklandığında çalışmak üzere aşağıdaki kodları yazıyoruz.

private void button1_Click(object sender,EventArgs e) {

            CacheFactory cf = new CacheFactory();

            Cache cacheDefault = cf.GetCache("default");

            cacheDefault.Put("uye",new Uye(textBox1.Text));

        }

        private void button2_Click(object sender,EventArgs e) {

            CacheFactory cf = new CacheFactory();

            Cache cacheDefault = cf.GetCache("default");

            Uye uye = (Uye)cacheDefault.Get("uye");

            if(uye != null) {

                textBox2.Text = uye.AdSoyad;

            } else {

                textBox2.Text = "<null>";

            }

        }

Yukarıda da gözüktüğü gibi CacheFactory’nin GetCache metodu ile Cache nesnesini elde edip, Get ve Put gibi metodlar ile istediğimiz anahtar ile veriyi kaydedip, kaydedilmiş veriyi okuyabiliyoruz.

Burada “default” olarak verilen cache ismi cache host üzerinde ClusterConfig.xml de belirlenmiş olan cache adıdır.

Administration tool aracılığı ile sunucu üzerindeki cachelenmiş veriler ile ilgili bilgilere erişebilirsiniz.

list cache ile cluster üzerindeki cache host bilgilerine eriştik. Ardından show hoststats ile cache host üzerindeki toplam cache verisi, toplam yapılan istek gibi istatistiki ve cache host durumunu gösteren bilgilere erişebiliyoruz.

Bu uygulamayı daha sonra aynı networkde yer alan farklı bilgisayarlardan da çalıştırıp ortak bir cache alanına sahip olduğunuz gözlemleyebilirsiniz.

Velocity’nin ASP.NET ve IIS üzerinde host edilen uygulama sunucusu rolündeki servisler ile entegrasyonu ile ilgili başka makalelere kadar konu ile ilgili çalışmalarınızla ilgili geri bildirim almaktan mutluluk duyacağım.



Team Foundation Server Nesne Modeli - TFSOM

Team Foundation Server’a Visual Studio ile bağlanmak için genellikle Team Explorer aracını kullanılır. Team Explorer TFS’e erişmek için Team Foundation nesne modelini kullanan bir istemci uygulamasından başka bir şey değildir. Team Explorer’in da kullandığı bu nesne modeli  “Team Foundation Server Object Model” .net kütüphanelerinden oluşan ve üçüncü parti yazılımların da kullanımını açık bir uygulama geliştirme arayüzüdür.

Team Foundation Nesne Modeli

Team Foundation Nesne Modelini oluşturan assembly dosyaları <sürücü>:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies klasörü altında bulunmaktadır.

Nesne modeli üzerinden bir işlem gerçekleştirilmek istendiğinde nesne modeli implementasyonu arka planda “Team Foundation Services” olarak genel bir ad altında toplanmış olan Team Foundation Server’in web servislerini kullanılır. Team Foundation Services web servisleri ise en son olarak arkaplanda sql server veritabanı üzerinde host edilmekte olan veriye ulaşmaktadır.

  Team Foundation Server uygulama geliştirme arayüzü alt yapı katmanları Team Foundation Services adındaki web servisleri Team Foundation Server’in kurulu olduğu işletim sistemi üzerinde Internet Information Services Manager aracılığı ile gözlemlenebilmektedir. Team Foundation Server tüm hizmetlerini IIS üzerinde host ettiği bu web servisleri ile vermektedir. Yani Team Foundation Server IIS üzerinde host edilmektedir diye özetleyebiliriz.

 Team Foundation Nesne Modeli ile neler yapılabilir?

Team Foundation Server’in  Version Control nesne modeline, Work Item Tracking nesne modeline, Team Build nesne modeline, Team Foundation Data Warehouse nesne modeline ve sistem genel bilgilerine(Team Foundation Server Core Services) erişilebilecek nesne modellerine TFS Nesne modeli kütüphaneleri ile erişilebilmektedir.

Team Foundation Server Nesne Modeli ile ilk uygulama

1.       Yeni bir Windows Forms Application projesi oluşturun.

2.       <sürücü>:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies  klasörü altından Microsoft.TeamFoundation.Client.dll ve Microsoft.TeamFoundation.dll dosyalarını referans olarak ekleyin.

3.       Aşağıdaki form tasarımını oluşturun.

 

Team Foundation Server’a bağlanmak için Microsoft.TeamFoundation.Client.TeamFoundationServer sınıfı kullanılır. Bu türden bir nesne oluşturmak için TeamFoundationServer sınıfının string parametre alan constructor overlodu kullanılabilir ancak bunun yerine TeamFoundationServerFactory sınıfının GetServer metodunu kullanmak performans açısından tavsiye edilir.

1: using System;
2: using System.Windows.Forms;
3: using Microsoft.TeamFoundation;
4: using Microsoft.TeamFoundation.Client;
5: namespace TFSOM1
6: {
7:     public partial class Form1 : Form
8:     {
9:         TeamFoundationServer tfsServer = null;
10:         public Form1()
11:         {
12:             InitializeComponent();
13:         }
14:         private void btnConnect_Click(object sender, EventArgs e)
15:         {
16:             //tfsServer = new TeamFoundationServer(txtTFSServerName.Text);
17:             tfsServer = TeamFoundationServerFactory.GetServer(txtTFSServerName.Text); //performans için bu tercih edilmelidir.
18:             this.txtInfo.Clear();
19:             writeInfo("AuthenticatedUserDisplayName", tfsServer.AuthenticatedUserDisplayName);
20:             writeInfo("ClientCacheDirectoryForInstance", tfsServer.ClientCacheDirectoryForInstance);
21:             writeInfo("Culture", tfsServer.Culture);
22:             writeInfo("HasAuthenticated", tfsServer.HasAuthenticated);
23:             writeInfo("InstanceId", tfsServer.InstanceId);
24:             writeInfo("Name", tfsServer.Name);
25:             writeInfo("TimeZone", tfsServer.TimeZone.StandardName);
26:             writeInfo("URI", tfsServer.Uri);
27:         }
28:         private void writeInfo(string propertyName, object value)
29:         {
30:             txtInfo.Text += (string.Format("{0:20} - {1}", propertyName, value.ToString()));
31:             txtInfo.Text += "\r\n";
32:         }
33:     }
34: }
35:  
 

Uygulamanın çıktısı aşağıdaki gibi gözükmektedir.

 

Yukarıdaki örnekte gözüktüğü gibi Team Foundation Server  core servislerine teamfoundationserver sınıfı ile erişebiliyoruz.

Ancak TFS nesne modeli ile erişebileceğimizden bahsettiğimiz diğer servislere erişmekte için GetService metodu kullanılır.

GetService metodu istenilen servisin type’ini alır ve geriye o servisin üzerinde işlem yapabileceğimiz nesnesini döner.

GetService ile elde edilebilecek servis listesi.

Service Tipi Açıklaması
IAuthorizationService Güvenlik ile ilgili işlemler yapılır.
ICommonStructureService Proje ve alt nodeları gibi sınıflandırma işlemleri yapılır.
IEventService Eventing mekanizması ile ilgili işlemler yapılır. Yani bir eylem gerçekleştiğinde şu işler yapılsın gibi tanımlamaları yapmak için uygun arayüzdür.
IGroupSecurityService Güvenlikte gruplama gibi işlemler.
ILinking Linkin servisi ile ilgili işlemler.
IProcessTemplates Team Foundation Server process templateleri ile ilgili işlemler.
IRegistration Registration verilerine erişmek için kullanılır.
IServerStatusService Team Foundation Server durumunu almak  için kullanılır.
VersionControlServer Version Control sistemi ile ilgili işlemler yapılır.
WorkItemStore Work Item Tracking sistemi ile ilgili işlemler yapılır.
 GetService metodu kullanımı

GetService metodu ile IServerStatusService nesne modeline erişerek server durumu ile ilgili bilgi almaya çalışalım. Bunun için aynı forma bir buton ekleyin ve adını btnServerStatus yapın. Butonun click eventine aşağıdaki kod yazın.

1: private void btnServerStatus_Click(object sender, EventArgs e)
2: {
3:     tfsServer = TeamFoundationServerFactory.GetServer(txtTFSServerName.Text);
4:     this.txtInfo.Clear();
5:     IServerStatusService statusService = (IServerStatusService)tfsServer.GetService(typeof(IServerStatusService));
6:     DataChanged[] statusResults = statusService.GetServerStatus();
7:     foreach (DataChanged statusResult in statusResults)
8:     {
9:         writeInfo("LastModified", statusResult.LastModified);
10:         writeInfo("DataType", statusResult.DataType);
11:     }
12: }
13:

Yukarıdaki kod bloğunda IServerStatusService arayüzünün type’ının GetService metoduna parametre olarak vererek geriye IServerStatusService interfaceini implemente eden Microsoft.TeamFoundation.Proxy.ServerStatusService türünde bir nesne döner. Bu metodun dönüş türü object olduğu için açıkca IServerStatusService tipine cast ederek dönüş nesnesini bir değişkene (statusService) alıyoruz. Artık statusService değişkenin gösterdiği nesnenin üzerindeki GetServerStatus metodu ile server durum bilgisini alabiliriz. Geriye dönen sonuç aşağıdaki ekran görüntüsünde gözükmektedir.

 

 

Team Foundation Server nesne modeli ile erişebileceğimiz diğer servisler ve hangi amaçlar doğrultusunda kullanılabileceklerini anlatacağım diğer makalelerim devam edecek. Örneğin WorkItemStore ile nasıl work itemlara erişebiliriz neler yapabiliriz sonraki makalelerimde bunları anlatıyor olacağım.

     

Work Item Type XML dokümanı yapısı

Daha önceki work item özelleştirme başlıklı makalemde work item nedir, neden özelleştirmek gerekir konusuna giriş yapmış ve witexport ve witimport komut satırı araçları ile work item xml dökumanını team foundation server’dan dışarıya almayı (witexport aracı ile) ve tekrar sisteme dahil etmeyi  (witimport aracı ile) örneklendirmiştim.

Bu makalede work item xml dökumanın şemasını inceleyip, adım adım sıfırdan bir work item tipi oluşturacağız.

Öncelikle mevcut bir bir work item’ın xml verisini export edelim ve genel hatlarını inceleyelim.

witexport /f c:\tfsfiles\task_template.xml /t BIZT /p testproject /n task

/f : export yapılacak olan dosyanın oluşturulacağı konumdur.Bu örnekte c:\tfsfiles\task_template.xml konumu verilmiştir.

/t : hangi team foundation servera bağlanılacağının belirlendiği parametredir. Bu örnekte BIZT adlı sunucuya bağlanılacaktır.

/p: team foundation server üzerindeki hangi team project üzerinden work item type export edileceğini belirler. Bu örnekte testproject adındaki team projectden export yapılacaktır.

/n: hangi work item type’ın export edileceğinin belirlendiği paramtedir. Bu örnekte task work item type’i belirtilmiştir.

Work Item Type – Genel hatları

Aşağıdaki resimde de gözüktüğü gibi bir work item tipi aşağıdaki temel bölümlerden oluşur. WITD root elemeti altında WORKITEMTYPE elementi  yer alır ve bu elemente verilen name özelliği ile work item typein sistemdeki adını belirler. Task,Bug,Requirement gibi.

 

DESCRIPTION : Work item type in ne iş için kullanılacağı ile ilgili genel bir bilgilendirme metni taşıyan elementdir.

FIELDS: Work item içinde yer alacak field’ların yani alanların tanımlandığı elementtir. Bu element altında tanımlanan fieldlar, form üzerinde gözükmek zorunda olan fieldlar değildir. Work item type form arabirimi üzerinden görüntülenecek ve üzerinde işlem yapılabilecek fieldlar tanımlanabileceği gibi arabirim üzerinde asla gözükmeyecek fieldlarda tanımlanabilmektedir. Ayrıca bu bölüm üzerinde hangi alanın hangi şekilde değere sahip olması gerektiği gibi tanımlamalar yapılır.

WORKFLOW: Work item typein durumlarının tanımlandığı elementtir. Örneğin Active durumda olan bir work item Closed duruma geçirildiğinde ClosedDate alanını otomatik değer atanması, Active duruma geçirilmiş bir work item’in tekrar New durumuna geçirilmemesi yada hangi durumlara geçirilebileceğinin belirlenmesi  yapılır.

FORM: Work item typein kullanıcı arayüzünün, hani fieldların görüntüleneceğinin belirlendiği elementdir.

Adım adım Work Item Type oluşturma

Work item customization işi ya kendi sürecinize göre bir work item type eklemek için ya da mevcut work item typeları yine sürece entegre etme adına özelleştirme için gerçekleştirilir.

Dağıtım (deployment) yani müştreye uygulamanın yüklenmesi işini work item ile takip etmek adına içerisinde aşağıdaki alanlar olan bir work item tipi oluşturmaya başlayalım adı DagitimPlani olarak belirleyelim.

Yeni DagitimPlani Work Item alanları

Durum : İşin durumu.

MusteriAdi : Hangi müşteriye yükleme yapılacağını belirler.Zorunlu değildir. Eğer bu alana bir değer girilmediyse tüm müşterilerde güncelleme yapılacaktır.

UygulamaAdi: Hangi uygulamanın müşteriye kurulacağını belirler

GerceklesmeTarihi: Hangi tarihte dağıtım işinin gerçekleştiğini belirler.

<?xml version="1.0" encoding="utf-8"?>

<witd:WITD version="1.0" xmlns:witd="http://schemas.microsoft.com/VisualStudio/2005/workitemtracking/typedef">

  <WORKITEMTYPE name="DagitimPlani">

    <DESCRIPTION>Müşteriye yapılacak dagitim işlerini yönetmek ve planlamak için kullanılır.</DESCRIPTION>

    <FIELDS>

      <FIELD name="State" refname="System.State" type="String">

        <HELPTEXT>İşin durumunu belirler.</HELPTEXT>

      </FIELD>

      <FIELD name="MusteriAdi" refname="CH.MusteriAdi" type="String">

       

      </FIELD>

      <FIELD name="UygulamaAdi" refname="CH.UygulamaAdi" type="String">

        <REQUIRED />

      </FIELD>

      <FIELD name="GerceklesmeTarihi" refname="CH.GerceklesmeTarihi" type="DateTime"/>

    </FIELDS>   

  </WORKITEMTYPE>

</witd:WITD>

 

Yukarıdaki xml elementi dagitimplani work iteminin belirlediğimiz gereksinimlerine göre fieldları içerecek şekilde yazılmıştır.

WORKITEMTYPE elementi içinde name özelliği verilerek yeni work item typein adının DagitimPlani olması sağlanmıştır.

FIELDS elementi içerisinde;

FIELD elemenleri tanımlanır, name alanı alanın adını refname alanı ise alanın daha sonra form üzerine kontrolleri eklerken kullanılacak olan referans adıdır.type özelliği ise bu alanın veri türünün ne olduğunu belirlemektedir.

WORKFLOW  ve FORM bölümlerini ekleyelim.

<?xml version="1.0" encoding="utf-8"?>

<witd:WITD version="1.0" xmlns:witd="http://schemas.microsoft.com/VisualStudio/2005/workitemtracking/typedef">

  <WORKITEMTYPE name="DagitimPlani">

    <DESCRIPTION>Müşteriye yapılacak dagitim işlerini yönetmek ve planlamak için kullanılır.</DESCRIPTION>

    <FIELDS>

      <FIELD name="State" refname="System.State" type="String">

        <HELPTEXT>İşin durumunu belirler.</HELPTEXT>

      </FIELD>

      <FIELD name="MusteriAdi" refname="CH.MusteriAdi" type="String"/>

      <FIELD name="UygulamaAdi" refname="CH.UygulamaAdi" type="String">

        <REQUIRED />

      </FIELD>

      <FIELD name="GerceklesmeTarihi" refname="CH.GerceklesmeTarihi" type="DateTime"/>

    </FIELDS>

    <WORKFLOW>

      <STATES>

        <STATE value="Bekliyor"/>

        <STATE value="Gerçekleştirildi" />

      </STATES>

      <TRANSITIONS>

        <TRANSITION from="" to="Bekliyor">

          <REASONS>

            <DEFAULTREASON value="Yeni" />

          </REASONS>

        </TRANSITION>

        <TRANSITION from="Bekliyor" to="Gerçekleştirildi">

          <REASONS>

            <DEFAULTREASON value="Dağıtım gerçekleştirildi." />

          </REASONS>

          <FIELDS>

            <FIELD refname="CH.GerceklesmeTarihi">

              <SERVERDEFAULT from="clock" />

            </FIELD>

          </FIELDS>

        </TRANSITION>

      </TRANSITIONS>

    </WORKFLOW>

    <FORM>

      <Layout>

        <Group>

          <Column PercentWidth="50">

            <Control FieldName="CH.MusteriAdi" Type="FieldControl" Label="Müşteri Adı" LabelPosition="Left" />

            <Control FieldName="CH.UygulamaAdi" Type="FieldControl" Label="Uygulama Adı" LabelPosition="Left" />

          </Column>

          <Column PercentWidth="50">

            <Control FieldName="System.State" Type="FieldControl" Label="Durum" LabelPosition="Left" />

            <Control FieldName="CH.GerceklesmeTarihi" readonly="true" Type="FieldControl" Label="Gerçekleşme Tarihi" LabelPosition="Left" />

          </Column>

        </Group>

      </Layout>

    </FORM>

  </WORKITEMTYPE>

</witd:WITD>

WORKFLOW elementi içerisinde ;

STATES elementi ve içerisindeki STATE elementleri ile bu work item typein alabileceği durumlar belirlenmektedir.

TRANSITIONS ve TRANSITION elemenleri ile hangi durumlar arasında geçişlerin yapılabileceği belirlenmektedir.

-Hangi durumdayken hangi duruma geçileceği.
-Bir duruma geçildiğinde yapılacak aksiyonların (bir fielda otomatik değer atanması gibi) belirlenmesi gibi adımlar burada gerçekleştirilir. Örneğin work item durumu Gerçekleştirildi olarak değiştirildiğinde readonly olarak belirlenmiş olan Gerçekleşme Tarihi alanına sistem tarihi otomatik olarak atılmaktadır.

FORM elementi içerisinde;

Bu elementi içerisinde esas olan Control elementidir. Bu element ile fieldlara karşılık gelen kontroller oluşturulabilir. Yukarıdaki örnekte Group kontrol eklenerek form iki sütuna (Column elementi ile) bölünmüştür. Column elementi içerisinde alt alta kontrolleri ekledikçe satılar oluşturulmuş olunur. Bu şekile yukarıdaki form dört hücreye bölünmüş olmaktadır.

Yukarıda oluşturduğumuz work item typeini team foundation içerisine dahil etmek için aşağıdaki komutu çalıştırmamız gerekmektedir.

witimport /f c:\tfsfiles\dagitimplani.xml /t BIZT /p testproject

Bu aracın parametrelerinin görevi witexport aracının parametrelerinin görevi ile neredeyse aynıdır.

Yukarıdaki resimde gözüktüğü gibi yeni oluşturduğumuz work item typei work item listesine eklenmiştir.

Dagitimplani form arayüzü ise aşağıdaki şekilde olacaktır.

Work item özelleştirme ile ilgili biraz daha detay vermeye çalıştığımız bu makalemizde şüphesiz ki work item xml dokümanı yapısını tam olarak incelemedik. Bunun referansı için msdn’i kullanabilirsiniz. Yada Team Foundation Server Power Toys kurup xml dökümanı ile muhatap olmadan work item özelleştirme işlemini gerçekleştirebilirsiniz.