SharePoint 2013 and Windows Server 2012 R2 – developer’s way

Yesterday I’ve tried to install SharePoint 2013 on Windows Server 2012 R2. Prerequisites installer run and suddenly it crashed on step ‚Application Server Role, Web Server (IIS) Role’. But wait, that is something new – never before had such a problem. Manual installation of Web Server Role also didn’t help – installer had just been stuck on this step. Just figured out that my last successful installation of SharePoint 2013 has been performed on Windows Server 2012 but not R2. Why bother then … for developer purposes only final result matters, so reverting back to Windows Server 2012 feels ok to me.

Reklamy

SharePoint–rozwiązywanie konfliktów zapisu

Jednym z częstych problemów występujących podczas developmentu rozwiązania dla SharePoint jest występowanie konfliktów zapisu. Sytuacja taka zachodzi gdy dopuszczona zostanie sytuacja w której dwóch lub więcej użytkowników może zmienić zawartość elementu listy jednocześnie (czy to poprzez wybraną architekturę rozwiązania, czy też przez błąd w kodzie). Problemem w stwierdzeniu (a właściwie uwierzeniu w to), że występuje konflikt zapisu, zwłaszcza przez początkujących jest komunikat występujący w tym przypadku. Zobaczmy zatem taką sytuację na przykładzie oraz potencjalny sposób jej rozwiązania.

W zaprezentowanym poniżej przykładzie zasymulowana została sytuacja próby jednoczesnej aktualizacji elementu listy przez dwóch użytkowników:

public partial class InitialPage : LayoutsPageBase
 {
    private SPList _employeesList; 
    public SPList EmployeesList
    {
        get
        {
            if (_employeesList != null)
            {
                return _employeesList;
            }
 
            return Web.GetList(string.Format("{0}{1}", Web.ServerRelativeUrl, "/Lists/EmployeesList")); 
        }
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            if (Page.IsPostBack)
            {
                // clear error message
                lblErrorMessage.Text = string.Empty; 
            }
        }
        catch (Exception ex)
        {
            ShowErrorMessage(ex);
        }
    }
 
    /// <summary>
    /// Adds one item to list
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void btnPopulateList_Click(object sender, EventArgs e)
    {
        try
        {
            SPListItem item = EmployeesList.AddItem();
            
            item[SPBuiltInFieldId.Title] = "First";
            item.Update(); 
        }
        catch (Exception ex)
        {
            ShowErrorMessage(ex);
        }
    }
 
    private void ShowErrorMessage(Exception ex)
    {
        lblErrorMessage.Text = ex.Message; 
    }
}
 

Powyższy kod jest wycinkiem dla utworzonego Application Page, przygotowującym do właściwych operacji. Przy deployu tworzona jest lista o nazwie “EmployeesList”, która po wciśnięciu przycisku “Populate list” wstawia na listę element o tytule “First”.

Zobaczmy teraz kod właściwy dla aktualizacji elementu listy przez dwóch użytkowników:

protected void btnSave_Click(object sender, EventArgs e)
{
    try
    {
        string name = txtName.Text.Trim();
        if (string.IsNullOrEmpty(name))
        {
            return;
        }
 
        // Simulate situation where two users try to update the same item at once
        SPListItem firstUserItem = EmployeesList.GetItemById(1);
        SPListItem secondUserItem = EmployeesList.GetItemById(1);
 
        // Try to update item 
        firstUserItem[SPBuiltInFieldId.Title] = name;
        secondUserItem[SPBuiltInFieldId.Title] = "concurrent change";
 
        firstUserItem.Update(); // ok - I was first
        secondUserItem.Update(); // error - save conflict
 
        // If exception not thrown then show message
        lblErrorMessage.Text = "Title of item has been changed";
    }
    catch (SPException ex)
    {
        ShowErrorMessage(ex); 
    }
    catch (Exception ex)
    {
        ShowErrorMessage(ex);
    }
}
Dla pierwszego użytkownika będziemy próbowali zmienić tytuł pobranego elementu na wpisany ciąg znaków do pola tekstowego. Drugi natomiast będzie próbował zmienić tytuł stałym wpisem “concurrent change”. Konflikt zapisu wystąpi w tym przypadku ponieważ dwóch użytkowników pobrało ten sam element z listy, pierwszy z nich zmienił tytuł i zdążył wykonać update na elemencie, zanim wykonał tę samą operację drugi. Zobaczmy jak to wygląda w praktyce:

conflict

Do pola tekstowego wpisany został tekst “changed by first”. Ze względu na to, że wystąpił konflikt zapisu dla drugiego użytkownika, który próbował zapisać tekst “concurrent change”, na liście pojawi się tekst wpisany do pola tekstowego:

conflict result

Rozwiązaniem dla konfliktu zapisu jest ponowienie operacji zapisu, z zaznaczeniem jednak, że element na którym chcemy wykonać operację musi posiadać aktualne dane zapisane do bazy contentowej. Element taki musi zatem zostać pobrany z listy ponownie w sytuacji kiedy wystąpił konflikt i jeśli ponownie nie zmieni on swoich danych w trakcie zapisu operacja zapisu powiedzie się. Wykrycie konfliktu zapisu następuje poprzez wyłapanie wyjątku typu SPException. Zobaczmy zatem odpowiednią modyfikację kodu dla zdarzenia btnSave_Click:

 

try
{
    // ... existing not modified coded
}
catch (SPException ex)
{
    // Exception has been thrown but that gave second user chance to update item once again 
    SPListItem secondUserConflictedItem = EmployeesList.GetItemById(1); 
    secondUserConflictedItem[SPBuiltInFieldId.Title] = "Save conflict but i'm gonna win :)";
    secondUserConflictedItem.Update();
}
catch (Exception ex)
{
    ShowErrorMessage(ex);
}
 

Po wyłapaniu wyjątku i zapisaniu zmian powinniśmy na liście zobaczyć zamiast tytułu elementu “changed by first” wstawiony w tym bloku tekst “Save conflict but i’m gonna win : )” :

second user wins

SharePoint – zmiana Display Name dla pola Title

 

Jednym z podstawowych problemów jaki napotykają początkujący programiści SharePoint jest zmiana nazwy wyświetlania dla wbudowanego pola Title.  Pole to jest obowiązkowym polem typu Text, umożliwia zatem przechowywanie ciągów znakowych o długości do 255 znaków. Bez problemu może być wykorzystane zatem do przechowywania takich danych jak np. imię czy nazwisko pracownika bez potrzeby tworzenia kolejnego dedykowanego pola. Ponadto, na liście, po najechaniu myszką na to pole uzyskujemy dostęp do menu kontekstowego pozwalającego m.in. edytować dany element listy. Przydałoby się więc, aby zawierało ono bardziej opisowy nagłówek niż “Title”, czy też “Tytuł”.

Dla pól utworzonych w Content Type’ie bez problemu można zmienić nazwę wyświetlania (Display Name) w stosunku do znajdującej się w zdefiniowanej kolumnie (Site Column) poprzez nadpisanie właściwości DisplayName. Sytuację te możemy zobaczyć na poniższych ekranach:

content type def

W definicji kolumny widać, że dla pola PersonName jako Display Name ustawiony został tekst “Nazwisko”, natomiast w referencji użytej w Content Type nazwa ta została zmieniona na “Nazwisko content type”.

new list item

Przechodząc do utworzenia nowego elementu listy widzimy, że nazwa “Nazwisko content type” została wyświetlona zarówno w widoku wszystkich elementów listy oraz na formularzu dodawania nowego elementu.

site column

Na liście kolumn witryny znajduje się natomiast zgodnie z oczekiwaniami nazwa “Nazwisko”.

Nieco inne zasady obowiązują jednak jeśli chodzi o zmianę nazwy wyświetlania kolumny Title. Przede wszystkim, aby odwołać się do tej kolumny przy definiowaniu Content Type’a należy znać jej GUID. W tym celu polecam użycie narzędzia SharePoint Manager 2010 dostępnego pod adresem http://spm.codeplex.com/ 

W celu zmiany nazwy wyświetlania musimy dysponować właściwie trzema GUID’ami – dla kolumn Title, LinkTitle oraz LinkTitleNoMenu. Po dodaniu referencji w Content Type dla tych pól jak na obrazku poniżej moglibyśmy oczekiwać zmiany nazwy pola:

 content type no change

Niestety jednak jeśli chodzi o Content Type nie przynosi to pożądanego skutku:

content type view

Umieszczenie tych referencji w Content Type pozwoli natomiast na automatyczne wygenerowanie referencji do pól przy tworzeniu List Definition, dzięki czemu nie trzeba ich ręcznie kopiować. W samej definicji listy trzeba jeszcze, poza referencją do pól, dodać definicję tych pól (tak jak została ona automatycznie dodana dla utworzonego wcześniej pola PersonName):

list definition title changed

Po takich zmianach widzimy, że nazwa pola uległa zmianie zarówno w widoku listy, jak i na formularzu dodawania nowego elementu (pamiętać należy jednak, że w Content Type nazwa ta bez zmian jest wyświetlana jako Title):

new list item title changed

SharePoint 2010 – w oczekiwaniu na Visual Studio 2011 cz. 2

 

Po zapoznaniu ze zmianami jakie na nas czekają przy budowie Content Type’ów przy pomocy Visual Studio 2011 zobaczmy jakich zmian możemy się spodziewać jeśli chodzi o tworzenie list. Zacznijmy zatem od dodania nowego elementu do projektu:

vs2011 new list

Pierwszą zmianę widzimy już na tym etapie, a mianowicie nie dostajemy już wyboru, czy chcemy utworzyć List Definition czy List Instance. Miejsce tych dwóch elementów zastąpił jeden nowy o nazwie “List”. Po dodaniu tego elementu widzimy w Solution Explorerze, że w projekcie utworzona została struktura taka, jak byśmy dokonali w starym stylu dodania List Definition wraz z instancją listy:

vs2011 solution explorer

Po dodaniu nowej listy przechodzimy do nowego designera, który ma za zadanie pomóc nam przy tworzeniu list:

vs2011 new list added

Do dyspozycji otrzymujemy trzy zakładki: List, Views oraz CommonProperties. Ostatnia zakładka odpowiedzialna jest za ustawienie właściwości listy takich jak Nazwa listy, jej opis oraz url pod jakim lista znajdzie się na serwerze. Możemy również zdecydować, czy chcemy umieścić listę na Quick Launch’u oraz czy lista ma być ukryta czy też nie.

W pierwszej zakładce, której widok został przedstawiony na powyższym obrazku, mamy możliwość dodania istniejących kolumn, zarówno tych zainstalowanych na serwerze, jak i dopiero co utworzonych w projekcie VS. Mamy również możliwość dodania Content Type’a do listy:

vs2011 custom content type

Do listy o nazwie PersonsList dodany został utworzony w poprzednim wpisie na blogu Content Type o nazwie ContentType1. Po tej czynności widok kolumn listy został uzupełniony o te, które zawarte zostały w dodanym Content Type’ie – w tym przypadku jedna kolumna o nazwie Person Name.

vs2011 after adding content type

Przechodząc do dobrze znanego nam pliku schema.xml widzimy, że zmiany zostały poprawnie odwzorowane w tym pliku, co zwalnia nas, przynajmniej w standardowych przypadkach, z konieczności ręcznej edycji wspomnianego pliku:

vs2011 after adding content type xml

W kolejnej zakładce designera dla list możemy zdefiniować nowe widoku dla listy lub zmodyfikować istniejące:

vs2011 list views

Również w tym przypadku zmiany poprawnie odwzorowywane są w pliku schema.xml:

vs2011 list views xml

SharePoint 2010 – w oczekiwaniu na Visual Studio 2011 cz. 1

 

W pierwszej odsłonie swoich zmagań z SharePoint’em chciałbym przedstawić pokrótce zmiany, jakie czekają na programistów SharePoint w nowej wersji Visual Studio (na dzień dzisiejszy jest to Microsoft Visual Studio 11 Version 11.0.40825.2 PREREL). Omawiane przeze mnie zmiany dotyczyć będą udogodnień wprowadzonych przy tworzeniu Content Type’ow oraz list. Już na pierwszy rzut oka widać tutaj zmiany na które z pewnością wielu programistów od dłuższego czasu czekało, bowiem nowa wersja VS oferuje nam designera, który ma na celu ułatwienie definiowania wcześniej wymienionych elementów. Z koncepcją designera dla Feature’ów i paczek dane było nam już się zaznajomić wraz z wersja VS2010, szkoda, że w owym czasie nie został wprowadzony również designer dla Content Type’ów a także wspomnianych już przeze mnie list.

Zobaczmy zatem najpierw jakie możliwości daje nam Visual Studio 2010, zaczynając od utworzenia projektu:

vs2010 new sharepoint element

Po wybraniu opcji “New Project” możemy utworzyć poza pustym projektem również szereg elementów składowych jak np. Content Type, czy List Definition bez konieczności umieszczania ich w projekcie SharePoint’owym. Wybierzmy jednak pusty projekt (podświetlona na szaro opcja na powyższym obrazku). Po jego utworzeniu, chcąc przystąpić do budowy Content Type’a dodajemy do projektu nowy element wybierając opcję Content Type:

vs2010 new content type

Jak można łatwo sprawdzić VS zajęło się dodanie nowego Content Type’a do istniejącego w projekcie Feature’a (o odpowiednim scope – web).  Jako tym bazowy został wybrany Item – po dwukrotnym kliknięciu w projekcie na nasz Content Type edytor przenosi nas do edycji pliku Elements.xml:

vs2010 new content type xml

Przystępując do budowy Content Type’a musimy zdefiniować nową Site Column wypełniając odpowiednie pola oraz generując nowy GUID dla tej kolumny. Następnie należy dodać referencję do zdefiniowanej Site Column. Nie jest to zbytnio skomplikowana czynność, w momencie gdy mamy jednak wiele kolumn czynność ta potrafi zabrać trochę czasu, a jakakolwiek pomyłka przy przeklejaniu kodu uniemożliwi poprawne zainstalowanie Content Type’a:

vs2010 site column

Zobaczmy teraz jak proces ten może usprawnić nowe VS. Zacznijmy ponownie od utworzenia nowego projektu. Już na tym etapie da się zauważyć zmiany, bowiem w nowej wersji liczba elementów które możemy utworzyć bez tworzenia najpierw pustego projektu jest bardzo ograniczona (widzimy jedynie możliwość utworzenia dwóch rodzajów Web Part’ów):

vs2011 new sharepoint element

Z kolejnych elementów możemy skorzystać standardowo dodając nowy element do projektu. Tutaj warto zwrócić uwagę na pojawienie się nowego elementu jakim jest Site Column, od której to zaczniemy tworzenie Content Type’a:

vs2011 site column

Po dodaniu Site Column o nazwie PersonName otwierany jest automatycznie plik Elements.xml, warto jednak zauważyć, że wiele z pól zostało już wypełnionych przez Visual Studio.

vs2011 new site column filled

Widzimy na powyższym obrazie m.in., że domyślnie założony został typ tekstowy, wygenerowany został GUID, a także słowa składowe nazwy zostały odpowiednio rozdzielone i wpisane do DisplayName. W dalszym ciągu definicja taka wymaga dalszej customizacji, jak np. zmiana typu itp. ale widać już postęp w porównaniu do poprzedniej wersji VS.

Przystąpmy dalej do budowy Content Type’a – po dodaniu tego elementu do projektu otwierany jest … no właśnie, w tym przypadku nie xml, ale nowy designer (warto zwrócić uwagę na to, że na etapie tworzenia domyślnie jako typ bazowy wybrany jest Item, dzięki czemu nie musimy za każdym razem przestawiać drop downa z domyślnego typu dla VS 2010 jakim było Announcements):

vs2011 new content type

W kolumnie DisplayName możemy wyszukiwać spośród dostępnych na serwerze Site Columns oraz jak widać także wśród tych stworzonych przez nas w projekcie. Po odnalezieniu odpowiedniej kolumny automatycznie wypełniany na podstawie definicji są kolumny Type oraz Required. Dzięki tej funkcjonalności, jeśli już posiadamy odpowiednie kolumny, to budowa Content Type’a  sprowadza się do ich wyklikania w designerze. Nic nie stoi na przeszkodzie, żebyśmy sprawdzili kod jaki wygenerował designer przechodząc do pliku Elements.xml – nie ma tutaj jednak większego zaskoczenia – zbudowany został on tak jakbyśmy sami wprowadzili odpowiedni kod:

vs2011 new content type filled

Widać więc, że nowe Visual Studio stara się ułatwić nieco życie programistom SP i chociaż częściowo odciągnąć od konieczności ręcznej edycji plików xml. Nie jest to zapewne milowy krok (nadal brakuje np. wyboru typu dla Site Column) ale zmiana ta powinna zostać doceniona jako krok w dobrym kierunku. W kolejnej odsłonie przekonamy się jakie zmiany czekają na nas w związku z tworzeniem list.