12 Temmuz 2011 Salı

Client Object Model nedir? Sharepoint 2010'da Silverlight Web Part nasıl kullanılır?

Sharepoint portalları üzerinde bugüne kadar asp.net teknolojisiyle geliştirilmiş user controlleri web part olarak host edebiliyorduk. Sharepoint 2010'da da bu durum devam etti. Ancak güçlü görselllere sahip ve kısmen istemci tarafında çalışan Silverlight teknolojisini de Sharepoint'te bir şekilde çalıştırmak gerekiyordu. Vee bunun için Sharepoint 2010'da geliştirilmiş olan Client Object Model kavramı ortaya çıktı.

Bu model ile, Sharepoint 2010 üzerinde, xap uzantılı Silverlight uygulamalarımızı Silverlight web part olarak host edip, çalıştığı portaldaki listeler üzerinde istenilen işlemleri yapabiliyoruz. Biz Silverlight üzerinden, client object modeli kullanırken, o arka planda Xml ve JSON formatında servisler ile Sharepoint Object Model ile haberleşerek server side işlemleri bizim için yürütüyor. Bu makalede adım adım Client Object Model kullanarak Silverlight web part geliştirmeyi ve uygulamamızı host etmeyi göreceğiz.

  1. İlk adım olarak Visual Studio 2010'umuzda yeni bir Silverlight projesi ya da mevcut Sharepoint 2010 solution'ımız üzerinde yeni bir Silverlight projesi açıyoruz. Zaten bir SharePoint solution'ı olan developer'lar daha derli toplu olması açısından ikinci seçeneği tercih edebilir. Bu şekilde yapmak (Sharepoint projelerinde package mantığı olduğundan dolayı deployment'ı da kolaylaştıracaktır.). Ben örnekte ilk seçeneği kullanacağım. Projeyi oluşturduktan sonra ilk işimiz proje referanslarına %WINDIR%\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin klasörü altında yer alan "Microsoft.SharePoint.Client.Silverlight" ve "Microsoft.SharePoint.Client.Silverlight.Runtime" dll'lerini eklemek. Bu dll'leri kullanarak Client Object Model'i kullanacağız.
















  2. Dll'leri ekledikten sonra Silverlight uygulamamızı geliştirmeye başlayabiliriz. Örnek olarak portalımızda bir listede yer alan elemanları çekip listeleyen bir uygulamaya yapalım. Öncelikle xaml tarafında gerekli elemanları yerleştirelim.
    <UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="SLWebPart.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
    <StackPanel Orientation="Vertical">
    <Button x:Name="btnGorevGetir" Content="Tüm Görevleri Getir" Click="btnGorevGetir_Click"
    Width="200" Height="50"></Button>
    <sdk:DataGrid x:Name="taskGrid" AutoGenerateColumns="True" />
    </StackPanel>
    </Grid>
    </UserControl>
    Xaml tarafına sadece görevleri çekme komutunun verileceği bir buton ve çekilen görevlerin doldurulacağı bir dataGrid yerleştirdik.



  3. Code behind tarafında yapacağımız işlem ise şu. Görevleri getir komutunu verecek butonun Click event'inde, Sharepoint listesinden elemanların çekilmesi işlemi ve bunların dataGrid'e doldurulması. Bu noktada Client Object Model kullanımı devreye giriyor. Buton Click eventimizi görelim:
    private void btnGorevGetir_Click(object sender, RoutedEventArgs e)
    {
    ClientContext spContext = new ClientContext("http://t1wsportal01/TalepYonetimi/");
    List taskList = spContext.Web.Lists.GetByTitle("Tasks");

    CamlQuery query = new CamlQuery();
    query.ViewXml = String.Format(@"<View><Query></Query></View>");

    taskCollection = taskList.GetItems(query);
    spContext.Load(taskCollection);
    spContext.ExecuteQueryAsync(OnSuccess, OnFailure);
    }
    Öncelikle Client Object Model dll'leri içerisinde yer alan ClientContext nesnesini, listemizin yer aldığı portal adresimizle yaratıyoruz. Daha sonra bu nesne üzerinden listemizin adı olan Tasks key'ini kullanarak SP listemize ulaşıyoruz. (Yeri gelmişken liste adı değişince bu kod patlayacağı için liste adını kullanmak doğru bir yaklaşım değil. Bu olası sorunu engellemek için listelerin internal name'leri üzerinden bu işlemi yapmak daha doğru olur daha ileriki makalelerde ona da değinirim).

    Listemize ulaştıktan sonra sorguyu yapacağımız CAML query'i hazırlıyoruz. Örnekte tüm listeyi çekmek istediğimiz için sorgumuzun içinde ekstra bir condition yok gördüğünüz üzere, ancak condition olacak durumlarda bildiğiniz CAML sorgusu ile dönen sonuçları daraltmanız mümkün. (Burada dikkat edilecek nokta da caml query sorgusunun başına ve sonuna tag'larini eklemek, yoksa hata alıyorsunuz ;) )

    Listemiz elimizde. Sorgumuz da hazır. Peki şimdi? Liste üzerinden GetItems metoduyla ilgili sorgumuzu çalıştırarak global tanımladığımız bir ListItemCollection'a liste elemanlarımızı çekiyoruz. Neden global? Çünkü Client Object Model ve Silverlight uygulamalarında tüm çağrılar asenkron oluyor. Yani elemanları listItemCollection'ımıza çektikten sonra hemen okuyamıyoruz. Asenkron bir çağrı sonucunda okuma işlemini yapabiliyoruz. Bu nedenle de collection'ımızı global tanımlıyoruz.

    ListItemCollection'ımıza gerekli atamayı yaptıktan sonra da ClientContext nesnemize load işlemi yapıyoruz ve asenkron çağrımızı gerçekleştiriyoruz. Bu executeQuery metodunun senkron bir overload'u da vardır. Eee o zaman hemen kullanalım?! Yok canım olmuyor :) UI içeren Client Object Model uygulamalarımızda mecburen asenkron çağrıları kullanıyoruz. Ama ola ki Console uygulaması yaparsınız bir gün o zaman senkron çağrıyı kullanabilirsiniz ;)

    Asenkron çağrı metodunda dikkat ederseniz OnSuccess ve OnFailure diye iki adet callback metot kullandım. Bu metotlar da asenkron çağrı başarılı veya başarısız olması durumunda callback yapılacak metotları ifade ediyor. Yani bu şu demek, bizim asenkron çağrımızın başarılı olması durumunda listItemCollection'ımızı okuma ve grid'e doldurma işlemlerini OnSuccess'in içerisinde yapacağız demek. Görelim;
    private void OnSuccess(object sender, ClientRequestSucceededEventArgs e)
    {
    SuccessDelegate delegateMethod = success;
    this.Dispatcher.BeginInvoke(delegateMethod);
    }
    private void success()
    {
    try
    {
    List<Task> taskList = new List<Task>();

    foreach (ListItem item in taskCollection)
    {
    Task newTask = new Task();
    newTask.GorevID = Convert.ToInt32(item["ID"]);
    newTask.GorevAdi = Convert.ToString(item["Title"]);

    taskList.Add(newTask);
    }

    taskGrid.ItemsSource = taskList;
    }
    catch (Exception ex)
    {
    MessageBox.Show("Exception from success: " + ex.Message);
    }
    }

    Burada dikkat edilmesi gereken nokta tüm operasyonların Dispatcher.Invoke içerisinde yapılması gerekliliği. Ben de debugging kolaylığı olması açısından bir delegate metot tanımlayarak Dispatcher nesnesinden çağrısını yapıyorum. Asıl operasyonun yapıldığı success metodunda yapılan da gördüğünüz üzere çok basit. Asenkron çağrı sırasında doldurduğumuz global listItemCollection'ımızda dönerek istediğimiz liste kolon değerlerini kendi tipimize atıyoruz. Daha sonra da grid'e kendi tipimizden bir koleksiyonu bağlıyoruz.

    Tüm kodu görelim;
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using Microsoft.SharePoint.Client;

    namespace SLWebPart
    {
    public partial class MainPage : UserControl
    {
    ListItemCollection taskCollection;

    private delegate void SuccessDelegate();
    private delegate void FailDelegate(Exception ex);

    public MainPage()
    {
    InitializeComponent();
    }

    private void btnGorevGetir_Click(object sender, RoutedEventArgs e)
    {
    ClientContext spContext = new ClientContext("http://t1wsportal01/TalepYonetimi/");
    List taskList = spContext.Web.Lists.GetByTitle("Tasks");

    CamlQuery query = new CamlQuery();
    query.ViewXml = String.Format(@"<View><Query></Query></View>");

    taskCollection = taskList.GetItems(query);
    spContext.Load(taskCollection);
    spContext.ExecuteQueryAsync(OnSuccess, OnFailure);
    }

    private void OnFailure(object sender, ClientRequestFailedEventArgs e)
    {
    FailDelegate delegateMethod = fail;
    this.Dispatcher.BeginInvoke(delegateMethod, e.Exception);
    }

    private void fail(Exception ex)
    {
    MessageBox.Show("Exception from fail: " + ex.Message);
    }

    private void OnSuccess(object sender, ClientRequestSucceededEventArgs e)
    {
    SuccessDelegate delegateMethod = success;
    this.Dispatcher.BeginInvoke(delegateMethod);
    }

    private void success()
    {
    try
    {
    List<Task> taskList = new List<Task>();

    foreach (ListItem item in taskCollection)
    {
    Task newTask = new Task();
    newTask.GorevID = Convert.ToInt32(item["ID"]);
    newTask.GorevAdi = Convert.ToString(item["Title"]);

    taskList.Add(newTask);
    }

    taskGrid.ItemsSource = taskList;
    }
    catch (Exception ex)
    {
    MessageBox.Show("Exception from success: " + ex.Message);
    }
    }
    }
    }
    Kendi veri tipimiz olan Task sınıfı ise;
    namespace SLWebPart
    {
    public class Task
    {
    public int GorevID { get; set; }
    public string GorevAdi { get; set; }
    }
    }


  4. Evett. Silverlight uygulamamız tamamlandı. Şimdi bunu Sharepoint 2010'da Silverlight Web Part olarak nasıl host edeceğiz? Şimdi bunun için birkaç yöntem var. Ben bu makalede birine değineceğim. Öncelikle Portal'ımızda "Xap Library" adında bir doküman kütüphanesi yaratıyoruz. Document Template'ini de "None" olarak değiştirelim.












    Daha sonra bu yarattığımız doküman kütüphanesine, Silverlight uygulamamızın build çıktısı olan xap uzantılı dosyayı ekliyoruz. Kendisi proje klasöründe Bin/Debug içerisinde yer alır. Silverlight uygulamamızı derledikçe yeni .xap dosyasını buraya yükleyeceğimiz için yükleme adımı sırasında "Overwrite existing files" demeyi unutmuyoruz.













  5. Xap dosyasını portalımıza yükledikten sonra son aşama olan bunu web part olarak bir sayfada göstermek kaldı. Bunun için XapLibrary doküman kütüphanemizde ilgili xap dosyamızın "Name" kolonundaki bağlantısına sağ tıklayarak "Properties"i seçiyoruz.























    Yeni açılan ekranda yer alan "Address (URL)" e karşılık gelen değeri kopyalıyoruz.
























    Portalımızda Silverlight web part'ı host edeceğimiz sayfayı açıyoruz veya böyle bir sayfa yoksa All Site Content -> Site Pages -> Add new page yolunu izleyerek web part'ı host edeceğimiz bir sayfa yaratıyoruz. Yaratılan sayfada üst menüdeki Insert tabından Web Part'ı seçiyoruz.









    Web part menüsünde solda Media and Content tipini seçip, daha sonra sağda açılan menüden Silverlight Web Part seçeneğini seçerek Add yapıyoruz.







    Açılan pop up ekranda, daha önce kopyaladığımız xap dosyasının library adresini yapıştırıp Ok'liyoruz.


















    Zaten bu noktada xap adresinde bir problem yoksa Silverlight uygulamamız direkt olarak sayfa içerisinde açılacaktır.

Silverlight uygulamamızı Sharepoint 2010 üzerinde host etmek işte bu kadar. Uygulamamızı test etmek için oluşturduğumuz sayfayı açıyoruz ve web part üzerinde "Tüm Görevleri Getir" butonumuza basıyoruz. Tasks listemizde yer alan tüm görevlerin grid'imizde gösterildiğini görüyoruz;

















Kontrol etmek açısından portalımızdaki Tasks listesini açıyoruz ve orada da aynı elemanların varolduğunu görüyoruz.






Sharepoint 2010 üzerinde, Silverlight uygulamaları kullanarak listelere erişmek bu şekilde mümkün oluyor. Listelerden veri çekilmesinin yanı sıra liste elemanları için tüm CRUD operasyonları ve liste işlemlerini de Client Object Model kullanarak yapmak mümkün.

Diğer operasyonların da bazılarını anlatan msdn bağlantısından da konu hakkında daha geniş bir bilgi elde edebilirsiniz.

Kolay gelsin,

Hiç yorum yok: