1 Aralık 2009 tarihi itibari ile 331. dönem olarak askerlik görevimi tamamlamak için bir süre buralardan uzaklaşıyorum. Dönüşte görüşmek dileğiyle.
İlker Çakır
WSS 3.0 - SharePoint 2007 - C# - Workflow - Tips/Tricks
1 Aralık 2009 tarihi itibari ile 331. dönem olarak askerlik görevimi tamamlamak için bir süre buralardan uzaklaşıyorum. Dönüşte görüşmek dileğiyle.
İlker Çakır
.NET yazılımcılarının program geliştirirken Linq kullanmaları ile (performans konsunda çok da net fikirlerim olmasada) hızlı geliştirme ve okunabilirlik konusunda çok yol katedildiği ortada.
Sharepoint te veriler ile çalışırken (ki genelde listelerde tutulur) hemen hemen her sharepoint yazılımcısı liste kayıtları üzerinde bir foreach kullanmıştır. Yaptığım küçük bir uygulama ile sharepoint te linq kullanımını göstermek istiyorum.
Uygulamamız Görevler listesinden “Tamamlanan” görevleri sorgulayıp yazdıran küçük bir web part uygulaması olacak. İlk olarak Linq kullanmadan önce verileri nasıl aldığımızı gösterelim:
İkinci olarak aynı işlemi Linq kullanarak nasıl yaptığımızı gösterelim:
Görüldüğü gibi çok daha az satır ve daha kolay okunabilir bir kod oluştu.
LinqToSharePoint projesini codeplex üzerinde ziyaret etmenizi tavsiye ederim.
Örnek web part projesini buradan indirebilirsiniz.
İlker
Sharepoint Microsoft.NET ailesinden ASP.NET ile geliştirilmiş bir ortamdır. Bu sebeple sharepoint üzerinde gördüğünüz herşey ASP.NET ile oluşturturulmuştur diyebiliriz. Sharepoint te sayfalarda solda ve üstte bulunan menülerde bildiğimiz asp:menü dür. İhtiyaçlarımız doğrultusunda oluşturmuş olduğumuz siteler için menülerimizi bizim belirlediğimiz bir yerden dinamik şekilde oluşturulmasını sağlamamız gerektiğinde izleyeceğimiz yoldan bahsedeceğiz.
Örnek olarak sharepoint te üstte yer alan menüyü (top navigation bar olarak isimlendirilir) sitemiz içerisindeki tüm listelerin yer alacağı şekilde özelleştirmeye çalışacağız.
Menümüzün özelleştirmeden önceki görünüm şu şekilde:
Çalışmamız için izleyeceğimiz yol:
1. Custom Site Map Provider ımız oluşturacağız. Bu işlemi System.Web içerisinde bulunan StaticSiteMapProvider sınıfından türettiğimiz bir sınıf ile gerçekleştireceğiz,
2. Geliştirdiğimiz provider ı sharepoint e tanıtacağız,
3. Sitemiz içerisinde üstte bulunan menünün (Top Navigation Bar) veri kaynağını oluşturmuş olduğumuz provider ı alacak şekilde ayarlayacağız.
Yeni bir VS.NET projesi açıp proje template i Class Library olarak belirliyoruz. İsimlendirme istediğiniz şekilde olabilir yalnız ilerleyen aşamalarda yapmış olduğunuz isimlendirme doğrultusunda hareket etmeniz gerekecektir. Projeye gerekli referanslarımızı ekleyerek başlıyoruz. İhtiyacımız olan referanslar:
1. Microsoft.SharePoint
2. System.Web
3. Sytem.Configuration
Referansların eklenmesi ile birlikte oluşturduğumuz sınıfı System.Web altında bulunan StaticSiteMapProvider sınıfından türetiyoruz. Türemeden dolayı gerekli olan iki adet method var:
1. BuildSiteMap
2. GetRootNodeCore
Bu metodları protected override olarak sınıfımıza ekliyoruz. Burada asıl işi gören metodumuz BuildSiteMap metotudur ve geriye SiteMapNode türünde bir nesne döndürür. BuildSiteMap metodu içerisinde sitemizde bulunan tüm listelerin isimlerini ve URL lerini ekleyecek şekilde geliştirmeyi yaptık ve sonuçta sınıfımız şu hale geldi:
Temel olarak kök bir SiteMapNode nesnesi oluşturduk ve diğer oluşturduğumuz tüm SiteMapNode nesnelerini bu kökün bir çocuğu olacak şekilde ekledik. Bu işlemi temel olarak aldığımız StaticSiteMapProvider nesnesi içerisindeki AddNode fonksiyonu ile gerçekleştirdik. Projemizi derleyip assembly cache e atıyoruz (geliştirdiğimiz kütüphanenin assembly cache içerisinde yer alması için kütüphaneyi imzalamamız gerekiyor, burada bu işlemlerden bahsedilmemektedir.)
İhtiyacımız olan SiteMapProvider sınıfını oluşturduktan sonra sitemizin web.config dosyası içerisinde gerekli tanımlamaları yaparak sınımızın kullanılabilir olmasını sağlayacağız. Bunun için web.config dosyası içerisine bulunan <siteMap> tagı içerisindeki <providers> tagına gerekli girdiği oluşturacağız.
Yukarıdaki resimde eklediğimiz satır CustomSiteMapProvider adı ile görülmekte.
Oluşturduğumuz ve tanımladığımız SiteMapProvider ın sharepoint üst menüsü tarafından görülebilmesi için master page içerisiden bir kaç değişiklik yapmamız gerekiyor. Sharepoint Designer kullanarak sitemizi açıyoruz. Sitemiz içerik ağacından:
_catalogs/masterpage
içerisinden default.master ı düzenlemek için açıyoruz. Sayfanın kod bölümünde “TopNavigationMenu” kelimesini arayarak üst menüyü oluşturan menü kontrolünü buluyoruz. Bu menü kontrolünün üst tarafına SiteMapProvider ımızın kullanılabilmesini sağlayacak olan bir delagate kontrolü ekliyor olacağız. Ekleyeceğimiz kontrolün yapısı:
<SharePoint:DelegateControl
runat="server"
ControlId="TopNavigationSiteMap2">
<Template_Controls>
<asp:SiteMapDataSource
id="customSiteMap"
SiteMapProvider="CustomSiteMapProvider"
runat="server" />
</Template_Controls>
</SharePoint:DelegateControl>
Burada dikkat etmemiz gereken husus SiteMapProvider özelliğinin web.config içerisinde tanımlama yaparken kullandığımız name ile aynı olması. Bu tanımlamayı yaptıktan sonra az önce bulmuş olduğumuz “TopNavigationMenu” kontrolünün “DataSourceID” değerini oluşturmuş olduğumuz SiteMapDataSource kontrolünün ID si ile eşitlemek (örneğimiz için: customSiteMap). Son olarak ekran görüntümüz şu şekilde:
İşlem tamam. Ana sayfanızı açarak üst menünüzün değiştiğini, siteniz içerisinde yer alan tüm listeler için bir bağlantı içerdiğini görebilirsiniz. Yeni oluşturacağınız her liste için menü otomatik olarak güncellenecek ve yeni oluşturulan liste için bağlantı bu menüde yer alacaktır.
İlker
Sharepoint iş zekası uygulamalarının geliştirilmesi için ideal bir platform olma özelliğine sahip. İşletmelerin rutin işlemlerinin dijital ortama atılması ile hem çalışanlar daha düzenli bir çalışma ortamına sahip oluyor hem de işletme için çoğu zaman önüne geçemediği karmaşıklığın giderilmesi sağlanıyor diyebiliriz.
Basit bir örnek ; İşletmede hazırlanan ve müşteriye gönderilecek olan teklif hazırlanıyor ve gönderilmeden önce birim amirine onaya gidiyor. Birim amiri dokümanı inceliyor basit bir not ile birlikte dokümanın hazır olduğunu belirtiyor, ya da tam tersi basit bir not ile doküman için düşüncesini ekleyip yeniden hazırlanmasını istiyor.
Oldukça basit olan örneğimizin işletmeye katkılarını listelemek gerekirse:
1. Hazırlanan doküman bir veya birden fazla kişi tarafından hazırlansa bile tek bir örnek üzerinde çalışılacağı için her zaman elimizde tek bir kopya bulunacak hem de en güncel hali ile,
2. Doküman üzerinde yapılan değişikliklerden haberdar olmak isteyen kişiler çok basit bir şekilde kendilerine uyarı gelmesini sağlayabilecekler,
3. Versiyon kontrol sistemi sayesinde doküman üzerinde kimin ne zaman değişiklik yaptığı tutulabilecek ve ihtiyaç duyulduğunda bir önceki versiyona geri dönülebilecek,
4. Hazırlanan doküman için son durum (Onaylandı/Reddedildi) kayıtlı olacak ve yine ihtiyaç doğrultusunda bu kayıtlar incelenebilecek,
5. Dokümanın en son gönderilen hali kayıtlı olacak ve basit bir arama ile elinizin altında her an ulaşabileceğiniz bir mesafede kalacak. Ayrıca aramada doküman içeriği de tarandığı için bulunma işlemi daha kolay olacak.
sistem basit olarak görünmekle birlikte küçük/orta işletmelerini genelinde bulunan karmaşıklıkların önüne geçmesi içn yeterli. Bir de bu sistem olamadan senaryomuzu düşünelim:
1. Bir veya birden fazla kişi bir teklif dokümanı üzerinde çalışmaya başladı. Her çalışan değil de bir çalışan dokümanı hazırladı ve diğerlerine gönderdi. Sonrasında diğer çalışanlar dokümanda güncelleme yaptı ve birbirlerine yine gönderdiler. Bir kaç e-postadan sonra her çalışanda bir kaç kopya ve dokümanın en son halini oluşturmak için uğraşan (kopyala/yapıştır yapan) bir kaç kişiden oluşan bir grup!
2. Dokümanlar zar zor birleştirildi ancak son halinde farkedildiki bir kişinin hazırladığı bölüm ortalarda yok. Tabii düzenlemede asıl kayıt üzerine yapıldığı için geri dönüş de yok, dolayısıyla yeniden bir çalışma ve zaman kaybı daha!
3. Doküman birim amirine gönderiliyor ve onay alınıyor, teklif iletiliyor fakat bir yanlışlık yapılmış. Yanlışlığın sebebi onay alınırken söylenen bir kaç maddenin tamamlanmaması. Yeniden bir tartışma, kim söylemişti, kime söylemişti, ne zaman söylemişti? yeni bir çalışma ve yine zaman kaybı!
4. Teklif bir şekilde hazırlandı ve gönderildi. Aradan aylar hatta yıllar geçti ve ihtiyaç oldu, dokümanın bulunması gerek. Bir ve bir kaç klasör içerisinde aranıyor taranıyor hatırlanmaya çalışılıyor sonuçta bulunuyor ya da bulunamıyor. Ya da bulunan doküman asıl gönderilen değilde hazırlanma aşamasında ortaya çıkan kopyalardan biri. Yeni bir zaman kaybı ve başarısızlık daha!
Göründüğü üzere basit olan bir işlev aslında ne kadar da derinlemesine problemlerden uzak durulmasını sağlıyor.
Başlangıç olarak dokümanımızı kaydedeceğimiz bir doküman kütüphanesine ihtiyacımız olacak. Doküman kütüphanesinin versiyonlama özelliğinin aktif edilmiş olması gerekiyor. (Kütüphanenin oluşturulmasını ve versiyonlama özelliğinin aktifleştirilmesinden burada bahsetmeyeceğim.)(Sharepoint designerın türkçe olmasından daha doğrusu olamamasından kaynaklanan bir karmaşılık mevcuttur)
Sharepoint Designer (buradan sonra kısaca SPD olarak yazılacaktır) ile üzerinde çalışacağımız siteyi açıyoruz. File->New->Workflow yolu ile yeni bir iş akışı çalışması başlatıyoruz. İsim olarak “Onay İş Akışı” belirledim. Başlangıçta formun alt tarafında bulunan “Variables…” butonu yardımı ile iş akışında kullanacağımız değişkenleri oluşturuyoruz. Akış esnasında 3 adet değişkene ihtiyacım olacak:
1. OnayDurumu: String tipinde, dokümanın onaylanıp onaylanmadığı bilgisini taşıyacak
2. OnayAciklaması: String tipinde, dokümanın onaylanma aşamasında girilecek açıklamayı taşıyacak,
3. OnayGorevListItemID, List Item ID tipinde, onay için oluşturulacak görevin görevler listesindeki ID değerini taşıyacak.
İlk olarak kullanıcadan veri toplama işlemini gerçekleştireceğiz. Bu işlemde arka planda belirleyeceğimiz kullanıcıya bir görev oluşturulacak ve bu görevin güncellenmesi için kullanılacak form SPD tarafından hazırlanacak. Action bölümünden “Kullanıcıdan Veri Topla” yı seçerek başlıyoruz.
Oluşan satırda “veri” bağlantısına tıklayarak açılan kutucuktan oluşturacağımız görev için bir ad (ve istersek açıklama) giriyoruz.
“Next” düğmesi ile bir sonraki bölüme geçiyoruz. Bu bölümde istediğimiz tipte istediğimiz değişkenleri oluşturabiliriz. Senaryomuzda onaylayan dokümanı onayla/reddet olarak seçimini belirtecek ve isterse açıklama girebilecekti. Bu sebeple Onay Durumunu ve Onay Açıklamasını tutacak olan değişkenleri tanımlıyoruz.
Bu işlem tamamlandığında arka planda SPD bizim için görev tabanlı bir içerik tipi oluşturup bu oluşturduğumuz alanları içerik tipine eklemektedir. Görevimizin takibi esnasında bu içerik tipini kullanıyor olacağız.
Alanların tanımlanması bittikten sonra görev sahibini belirleyeceğimiz ekrana “bu kullanıcı” bağlantısına tıklayarak ulaşıyoruz. Ekranda maili göndereceğimizi kişi ya da kişileri belirleyebileceğimiz bir kaç seçenek bize sunuluyor olacak. Bu örnekte mevcut kullanıcılardan birini belirledik ve tamam diyerek bu aşamayı da geçiyoruz.
Veri toplama aşamasında son olarak “Variable: toplama” bölümünü kullanarak açılan listeden önceden oluşturduğumuz “OnayGorevListItemID” değişkenini seçiyoruz.
İstediğimiz bilgileri onaylayan kullanıcıdan aldık, şimdi sıra bu değerleri workflow içerisinde kullanmamızı sağlayacak olan ilk adımda oluşturduğumuz değişkenlere aktarmakta. Bu işlem için “Actions” menüsünden “İş Akışı Değişkenin Ayarla” yı seçiyoruz.
Bu adım biraz aklımızı karıştırabilir o sebeple biraz alt tarafta neler oluyoru biraz açıklayalım. Görevler (Tasks) listesinde onay görevimiz ile ilgili bilgiler duruyor ve bu bilgileri alıp değişkenlerimize aktaracağız. Görevler listesinde bir çok görev olacaktır ve bizim bu listede az önce kullanıcaya oluşturduğumuz ve onunda seçeneklerini girdiği görevi bulmamız gerekmekte. Oluşturduğumuz görevin kayıt ID sini az önce “OnayGorevListItemID” adlı değişkenimize aldığımızı hatırlayacaksınız. İşte bu ID li göreve ulaşıp istediğmiz değerleri değişkenlerimize aktaracağız.
Bu aşamda “değer” bağlantısı ile küçük bir form açılacaktır. Açılan formda ilk olarak görevler listemizi (bu örnek için “Tasks” isimlidir) ve buradan almak istediğimiz alanı seçiyoruz. Formun alt tarafında yer alan “Find The List Item” bölümünde ise seçmiş olduğumuz liste içerisinden ihtiyacımız olan kaydı nasıl bulacağını SPD ye anlatıyoruz. Görevlerden Kimlik alanı (Tasks:Kimlik) eşittir önceden kaydettiğimiz ID değerine (“OnayGorevListItemID” workflow data içerisindedir) eşit olan kayıt. Bu şekilde her iki bilgiyi ( Onay durumu ve onay açıklaması nı) değişkenlerimize alıyoruz.
İhtiyacımız olan bilgileri aldık şimdi sırada kullanıcının tercihine göre nasıl bir aksiyon alacağımıza karar vermekte. Ana formun sağ tarafını kullanarak yeni bir iş akışı adımı ekliyoruz.
Bu adımda eğer kullanıcı “Onaylandı” seçeneğini seçmiş ise dokümanı oluşturan (doküman kütüphanesine ekleyen) kullanıcıya onaylandı maili, “Reddedildi” ise reddedildi maili göndereceğiz ve her iki mailde de onaylama işlemini yapan kişinin açıklaması yer alacak.
İkinci adımdaki formda “Conditions” bölümünden “Herhangi bir veri kaynağını karşılaştır” ı seçiyoruz. “değer” bağlantısı ile “Workflow Data” bölümünden “OnayDurumu” değerini karşılaştıracağız. Karşılaştıracağımız değer ise “Onaylandı”. Sonrasında “Actions” bölümünden “E-Posta Gönder” i seçerek şartımızın gerçekleşme durumunda hangi aksiyonu alacağını seçiyoruz.
Senaryomuzda yer aldığı gibi onaylanma ve reddedilme durumlarından her ikisindede dokümanı yükleyen kişiye yani kaydı oluşturan kişiye mail atacağız. Bu sebeple mail alıcısı olarak “User who created current item” seçeneğini seçiyoruz. Mail içeriği olarak belirlediğimiz herhangi bir içeriği ekliyoruz. Burada kullanmak istediğimiz ve daha önce onaylayan tarafından girilen açıklama alanını mail içeriğini hazırlarken sol altta bulunan “Add Lookup to Body” butonunu kullanarak açılan formdan “Workflow Data” içerisindeki “OnayAciklamasi” ni seçerek ekliyoruz.
Birinci şartımızın sağlanmamış olma durumu yani onay durumunun “Reddedildi” olma durumunu yakalamak amaçlı “Add Else-If Condition” bağlantısı ile sağlıyoruz. Bu aşamadaki aksiyonumuz yine kaydı oluşturana mail atmak olacak tek fark mail içeriğini değiştiriyor olacağız. Son aşamada ikinci adımımızın görüntüsü şu şekilde:
Ve workflow umuz hazır, “Finish” butonu ile iş akışını tamamlıyoruz.
Şimdi doküman kütüphanemiz üzerine eklediğimiz doküman üzerindeki menüyü kullanarak iş akışımızı başlatabiliriz.
İş akışı başlatmada kullandığımız formu SPD otomatik oluşturmuştur. SPD içerisinden workflow bölümünden oluşturduğumuz workflow içerisinde bu form bulunmaktadır buradan istediğiniz değişiklikleri yapabilirsiniz. İş akışı başladığında doküman kütüphanesi üzerindeki kayıtta durumu yer alacaktır.
İş akışı öncelikle görev sahibine bir görev atayacak ve otomatikman görev sahibine bir mail ulaşacaktır.
Görev sahibi bu görevi bu maildeki bağlantıdan ya da site üzerindeki görevlerim bölümünden görüntüleyebilir.
Görevin düzenlenmesi durumunda SPD nin bizim içi oluşturmuş olduğu sayfa gelecektir. Yine bu sayfayı da istediğiniz şekilde özelleştirebilirsiniz.
Görevin tamamlanması ile iş akışımız bir karar verecek ve karar doğrultusunda dokümanı oluşturana mail atacaktır.
Bu şekilde iş akışımız sonlanacaktır ve doküman üzerindeki akış durum alanı “Tamamlandı” olarak güncellenecektir.
İlk başta bahsettiğimiz akış tarihçesi için SPD içerisinde bir tanımlama yapmadık iş akışı geliştirilirken “Actions” içerisinde yer alan “Geçmiş listesinde günlük kaydı tut” ile istediğiniz herhangi bir kaydı buraya atabilirsiniz.
Yapmış olduğumuz örnek temel amaçlıdır, bir iş akışının geliştirilmesi aşamaları adım adım anlatılmıştır. Örnekte de görüldüğü üzere Sharepoint Designer ile çok basit şekilde ihtiyacımız olan fazla kompleks olmayan iş akışlarını hızlı bir şekilde tasarlayabiliyoruz. Kullanıcılardan bilgi toplayıp bu bilgiler ile akışı yönlendirip yine bu bilgiler ile kullanıcıları besleyebiliyoruz. Burada bahsetmediğimiz aksiyonlar ile daha fazla iş yapabilmemiz de mümkün olmaktadır.
Umarım yararlı olmuştur.
İlker
Sharepoint bünyesindeki feature kavramı ile geliştiricilere ihtiyacı olan düzenlemeleri gerçekleştirebilmeleri için yeni bir yol sundu. Feature lar aslında XML tabanlı birer dosyadan başka bir şey değil. XML dosyasını eğer sharepointin kurallarına uyarak düzenlemişseniz tam olarak ihtiyacınız olan davranışı sağlamışsınız demektir.
Feature lar ile CustomAction denilen ve bize sunulan bir kaç lokasyona bağlantılar (ve araç çubuğu elemanları)yerleştirmemizi sağlayan özelliği içeriyor. Custom Action lar ile bağlantılarımızı yerleştirebileceğimiz yerleri msdn listelemiş, liste uzun olduğu için burada paylaşmıyorum. Bağlantı:
Default Custom Action Locations:
İhtayacım doğrultusunda özel bir listenin yeni kayıt ekranı araç çubuğunda (NewForm Toolbar) bir bağlantıya ve bu bağlantının da yeni küçük bir ekranda başka bir listeye yeni kayıt ekleme ekranına açılmasını sağlamaya çalıştım. Adımlar şu şekilde:
1. İhtiyacımız olan bağlantıyı oluşturacak Feature Element dosyasını hazırlamak:
Yukarıdaki görüntüde bir custom action element i için gerekli özelliklerin girilmiş hali gözükmekte.
2. Hazırlamış olduğumuz custom action ı aktifleştirmek:
Not: Burada element.xml dosyasının feature içinde nasıl sharepoint e ekleneceğinden bahsetmedim, sadece son hali yer almakta (Ek olarak aynı şekilde hazırlanmış Yeni Kurum bağlantısı ile birlikte).
Burada istediğimiz formatta hazırlanmış bağlantımızın listemizin yeni kayıt ekranına yerleştiğini görüyoruz. Bağlantıya tıkladığımızda yeni bir ekranda açılmasını sağlayan özellik ise yukarıda yer alan element.xml dosyasındaki:
<UrlAction Url="javascript:void window.open('{SiteUrl}/Lists/Evrak%20Konular/NewForm.aspx','','location=0,status=0,scrollbars=0');return false;"/>
satırıdır. Bu satırı incelediğimizde Url olarak bir javascript işlemini işaret ettiğimizi görüyoruz. Bu bölüme dikkat: javascript: den sonra yer alan void i eklemediğinizde yeni bir ekranda açılma isteği sağlanmayacaktır. Onun dışındaki tüm satır standart javascript girişidir.
NOT: Yeni arkadaşlar için {SiteUrl} yabancı gelebilir. Bu kelime sharepoint içerisinde tanımalnmış bir kaç özel kelimeden biridir. Şöyle bir liste sanırım yardımcı olacaktır:
| ~site/ | SPContext.Current.Web.ServerRelativeUrl |
| ~sitecollection/ | SPContext.Current.Site.ServerRelativeUrl |
| {ItemId} | item.ID.ToString() |
| {ItemUrl} | item.Url |
| {SiteUrl} | web.Url |
| {ListId} | list.ID.ToString(“B”) |
| {RecurrenceId} | item.RecurrenceID |
İlker