Ostatnio potrzebowałem napisać mechanizm do zarządzania własnościami SPWeb(SPWeb.Properties), na tyle prosty i przejrzysty by każdy mógł z niego skorzystać.

Jak to zwykle w projektach SharePoint, moim pierwszym miejscem gdzie szukałem rozwiązania był Google ;) pamiętam do tej pory, że widziałem już takie rozwiązanie gdzieś dostępne… było to dawno temu jednak wiem, że ktoś już wykonał tą mozolną i prostą pracę napisania tego – jeżeli macie gdzieś linka, to podajcie, z chęcią je zobaczę :)

Niestety, nie udało mi się w założonym czasie znaleźć tego co szukałem, więc stwierdziłem, że mam jeden wolny wieczór więc to napiszę. – hop siup i po sprawie. Dla tych, którzy nie wiedzą, SPWeb.Properties umożliwiają przechowywanie DicionaryEntry: klucz – wartość. Wartości przechowywane dostępne są na poziome Web (nie site collection) przez co można niektóre sprawy konfiguracyjne tam przechowywać. Przykładem aplikacji intensywnie wykorzystującej SPPropertyBag jest darmowe rozwiązanie do zarządzania elementami na listach, które mają być wyświetlane i kiedy podczas tworzenia, edycji i wyświetlania elementu (rozwiązanie dostępne na CodePlex).

Ogólnie zabawa samym SPPropertyBag jest bardzo, ale to bardzo prosta:

SPPropertyBag bag = web.Properties;
 
// Dodanie elementu
bag.Add("klucz", "wartosc");
bag.Update();
 
// Edycja elementu
bag["klucz"] = "wartosc";
bag.Update();
 
// Usuniecie (o tym wiecej na blogu)
bag.Remove("klucz");
bag.Update();
 
// Sprawdzenie czy klucz istnieje
if(bag.ContainsKey("klucz"))
    Console.WriteLine(bag["klucz"]);
 
// Sprawdzenie czy wartosc istnieje
if(bag.ContainsValue("wartosc"))
{
    // kod dzieki uprzejmosci %
    var keys = bag.Cast<DictionaryEntry>()
        .Where(de => de.Value == "wartosc")
        .Select(de => de.Key).ToList();
 
    foreach(var key in keys)
    {
        Console.WriteLine("klucz: {0} posiada wartosc: {1}", key, "wartosc");
    }
}

Jak sami widzicie nie ma w tym nic skomplikowanego. Jedynie o czym trzeba pamiętać o aktualizacja SPPropertyBag po każdej akcji dodania, aktualizacji lub usunięcia (uwaga o tym zaraz).

Więc co… zabieram się do pracy, tworzę stronę z SPGridView wyświetlającą wszystkie klucze i wszystkie wartości, dodaje możliwość sortowania, filtrowania, dodaje przyciski do edycji, usuwania oraz przycisk Toolbar do dodania nowej wartości. Stronka wyświetlająca już śmiga, więc zaczynam podpinać stronę do dodania (super, bez problemu), stronę do edycji (lekka modyfikacja strony dodającej) no i pozostała mi ostatnia funkcja… usunięcie wartości z SPPropertyBag.

Odpalam stronę, kasuje wartość a ona znika… super! No więc dla testu usunę jeszcze jeden element… i on znika! Ekstra… ale… co jest… element który został pierwszy usunięty znów się pojawił… Wchodzą znowu na stronę i znów wszystkie wartości są dostępne. No więc patrzę na swój kod:

// Usuniecie
bag.Remove("klucz");
bag.Update();

Wygląda poprawnie. Patrzę na kod od SPGridView, też wygląda poprawnie, więc olewam go. Tworzę Console Application i tam zaczynam testować. Wywołuje funkcję sprawdzającą czy klucz testowy istnieje i jeżeli istnieje to go usuwam:

if(bag.ContainsKey("klucz"))
{
    Console.WriteLine("Usuwam klucz-wartosc: {0}-{1}", "klucz", bag["klucz"]);
    bag.Remove("klucz");
    bag.Update();
 
    if(bag.ContainsKey("klucz"))
    {
        Console.WriteLine("ERROR: Cos poszlo nie tak...");
    }
}

Poszczególne wywołania aplikacji (kolejno 5) zwróciły mi:

Usuwam klucz-wartosc: klucz-wartosc

Usuwam klucz-wartosc: klucz-wartosc

Usuwam klucz-wartosc: klucz-wartosc

Usuwam klucz-wartosc: klucz-wartosc

Usuwam klucz-wartosc: klucz-wartosc

Coś chyba nie tak? Patrzę więc na debug, po usunięciu klucza, wartość znika z SPWeb.Properties, ale jak ponownie wykonuje program, to ta wartość tam istnieje. Myślę sobie, dobra, pewnie coś tam jest aktualizowane w meta danych SPWeb więc należy dodać:

web.Update();

i kłopot z głowy. Więc robie kolejne testy… i dalej nic. Dobra to przed usunięciem elementu, zeruje wartość (może automatem go usunie?):

if(bag.ContainsKey("klucz"))
{
    Console.WriteLine("Usuwam klucz-wartosc: {0}-{1}", "klucz", bag["klucz"]);
    bag["klucz"] = string.Empty;
    bag.Update();
 
    bag.Remove("klucz");
    bag.Update();
 
    web.Update();
 
    // na wszelki wypadek
    bag = web.Properties;
 
    if(bag.ContainsKey("klucz"))
    {
        Console.WriteLine("ERROR: Cos poszlo nie tak...");
    }
}

Wynik jakoś mnie nie zdziwił. Wartość znowu nie została usunięta. Więc po raz kolejny zaglądam w Google i czytam te wszystkie posty jak to prosto jest usunąć wartość z SPPropertyBag. Mówiąc szczerze banał nie? Prawie jak ustawienia „Now Playing” w Windows Communicatorze.

W końcu po wielu przejrzanych stronach natrafiłem na ten sam problem… Chrissy Blanco, na swoim blogu opisuje dokładnie ten sam problem.

Morał z dzisiejszego postu jest taki: nie zależnie co mówi dokumentacja, my programiści wiemy lepiej!

Tak na wszelki wypadek:

SPPropertyBag.Remove nie działa

SPPropertyBag.Romove does not work

SPPropertyBag.Remove no funciona

PS.: jak znacie rozwiązanie na ten problem… to z chęcią o nim usłyszę

PS2.: funkcjonalność weryfikowałem pod WSS 3.0 SP1 ENG

4 KOMENTARZE

  1. Jedyne rozwiązanie:

    web.Properties[“klucz”] = null;
    web.Properties.Update();

    Moze naprawia w SP2.

    Pozdrawiam,

  2. @woro

    jak juz kodzik MSowy wchodzi w metadane pochowane w dziwnych ustawieniach do ktorych nie ma dosc zrozumialego dostepu (jak na przyklad przy SPList.ItemCount) to rezygnuje z dalszej analizy, bo w 90% konczy sie ona na wywolaniu SPRequest…

    @Michal

    No, tak samo jak string.Empty, ale to nie zalatwia sprawy :( Trzeba porpsotu o tym wiedziec i w features dla swoich solution pamietac o tym ze jak sie tworzy klucz to nalezy sprawdzic czy on aby na pewno nie istnieje.

    Tez mam nadzieje, iz SP2 to naprawi… ale nie sadze, to bdzie bug i tyle :/ juz raczej wiekszosc zespolu siedzi nad doszlifowywaniem MOSS 2010 aka MOSS 14

  3. Zgadzam się z Tobą.

    Super artykuł.

    Tak btw czekam na jakieś wirtualki z wczesnymi wersjami MOSS’a 2010, aby zweryfikować kilka ciekawostek jakie znalazłem w obecnej wersji MOSS’a.

Comments are closed.