wtorek, 11 czerwca 2013

Odwołanie się do kontrolki DevExpress za pomocą javascript

Jednym z ważnych aspektów pisania efektywnego i przyjaznego dla użytkownika kodu aplikacji webowych, jest umiejętne wykorzystywanie języka javascript umieszczonego w przeglądarce. Aby efektywnie korzystać z tego języka, należy umieć odwoływać się do obiektów.
Standardowo, w języku javascript do obiektów dokumentu odwołujemy się poprzez metodę 'document.getElementById()':

<dx:ASPxButton ID="ASPxButton1" runat="server" AutoPostBack="False" Text="Get text">
</dx:ASPxButton>

<script type="text/javascript" >
     var editorClientId = "<%=ASPxButton1.ClientID%>";
     var editor = document.getElementById(editorClientId);
     //Do something
</script>


Niestety, ale taka, standardowa dla języka javascript opcja, w przypadku kontrolek DevExpressa nie zadziała. W przypadku kontrolek DevExpressa, aby odwołać się do naszych kontrolek w języku javascript mamy dwie możliwości:

a) nadać kontrolce sztywne 'client id', tak jak zostało to opisane w tej odpowiedzi supportu.. Niestety takie rozwiązanie ogranicza nas do jednej instancji tej kontrolki na stronie:

<dx:ASPxPopupControl ID="ASPxPopupControl1" runat="server" ClientInstanceName="popupControl" ></dx:ASPxPopupControl>

 <script type="text/javascript" >
  popupControl.Show();
 </script>

b) wykorzystać metodę 'ASPxClientControl.GetControlCollection().GetByName()', która jest DevExpressowym odpowiednikiem 'document.getElementById()'. Sposobów jak to zrobić jest kilka. Jeden z nich umieszczony został w dokumentacji. Inny przykład:

        <dx:ASPxGridView ID="grid" runat="server" CssClass="gridRelatedDocs" AutoGenerateColumns="False" Width="100%"
        GridLines="None" style="padding-left: 0px;padding-right: 0px;">
            <Border BorderStyle="None" BorderWidth="0px" />
            <SettingsBehavior AllowDragDrop="False" />
            <Settings ShowFilterRow="True" />
            <SettingsPager >
                <Summary Visible="False" />
            </SettingsPager>
        </dx:ASPxGridView>

<script language="javascript" type="text/javascript">
    function DoSomething() {

        var grid2 = $('.gridRelatedDocs');
        if (grid2 != null && grid2[0] != null) {
            var grid = ASPxClientControl.GetControlCollection().GetByName(grid2[0].id);
            //grid.DoSomething
        }
    }
 </script>

Generalnie sposób nr. 2 jest bardziej przyjazny i uniwersalny. Wprawdzie najpierw musimy ustalić id elementu w hierarchii struktury drzewa DOM, ale posiadając już standardowy, 'javascriptowe' id obiektu możemy się nim posługiwać w standardowy sposób. Wykorzystanie rozwiązania z 'ASPxClientControl.GetControlCollection().GetByName'  pozwala na umieszczenie wielu kontrolek tego samego typu na jednej stronie asp.net.

poniedziałek, 10 czerwca 2013

Wstep do kontrolek DevExpress

Jak zapewne wielu programistów wie, jedną z najgorszych rzeczy, jakie można robić będąc programistą, to wymyślanie koła od nowa. Aby tego nie robić, powstały frameworki (np. .NET Framework), wzorce projektowe, rozszerzalne biblioteki (np. jQuery, pdf-libraries) i wiele, wiele innych. Część udostępnianych na darmowych licencjach (np. Licencja X11 (MIT)), a część na licencjach komercyjnych.
Takim przykładem komercyjnego oprogramowania, a dokładniej kontrolek wykorzystywanych w środowisku '.NET' są kontrolki firmy  DevExpress. Kontrolki, które nie są tanie (link do cennika) i kupowane są 'per developer'. Tak, moi mili. Te ceny, które są tam umieszczone dotyczą ceny, za możliwość wykorzystywania oprogramowania przez pojedyńczego programistę i kształtują się od $900 za najmniejszy pakiet (np. dla programisty asp.net) do pakietu full ($2199 per programista).

Co za tą cenę dostajemy?
Hmmm, chyba najlepsze kontrolki programistyczne, jakie można dostać w .net ;)
Programując z ich wykorzystaniem programista naprawdę zyskuję sporą przewagę nad rozwiązaniami darmowymi, a co za tym idzie programowanie idzie szybciej, sprawniej, jest ładniejsze i zawiera mniej błędów. Przede wszystkim uzyskujemy kod wykorzystywany i sprawdzony przez miliony ludzi. Firma devExpress wygrywała ze swoimi kontrolkami wiele międzynarodowych konkursów, przez co jej popularność rosła, a wraz z nią ilość ludzi którzy bezpośrednio (developerzy) oraz pośrednio (użytkownicy ich programów) z nich korzystali na co dzień. Jedną z największych zalet wynikających z tych kontrolek jest właśnie to, że jak coś się miało popsuć, lub 'nie wyjść' to bardzo prawdopodobne, że wcześniej popsuło się komuś innemu i ekipa z devxpressa już ten problem rozwiązała, lub właśnie nad nim pracuje ;)
Oczywiście, nie ma róży bez kolców, ale o tym nieco później.

Najpierw jednak przyjrzyjmy się tym kontrolkom nieco bliżej. Jak przykład użyję kontrolek asp.net, jako, że są to kontrolki webowe i istnieje całkiem niezłe 'on-line' demo. Jedną z najlepszych, a zarazem najczęściej używanych jest DevExpressowy odpowiednik AspxGridView.
Zalecam zapoznanie się z demem tego grida, ponieważ posiada naprawdę potężne możliwości (np. utworzenie rozwiązania, wyświetlającego 300.000 rekordów w kilka min. z rewalacyjną, jak na taką ilość danych szybkością wyświetlania, sortowania, filtrowania itp.).

Do tego dochodzą wszelakie możliwości kontrolek DevExpressa, czyli multum opcji i pełna konfigurowalność (a w pakiecie ultimate również kody źródłowe kontrolek). Po tym, jak programista zobaczy, ile jest opcji konfiguracyjnych dla danej kontrolki by deafult (a drugie tyle w tutorialach i Q&A na forum wsparcia) to później zwykłe .net-owe kontrolki wyglądają mega blado.

Tak jak już zostało wspomniane, aspxGridView nie jest jedyną kontrolką, jaka isntieje w pakiecie. Generalnie zasada jest taka, że każda kontrolka wystepująca w standardowym GUI .NET Framework ma tutaj swoje devExpressowego odpowiednika. Do tego dochodzą jeszcze inne, mniej lub bardziej przydatne kontrolki standardowo nie występujące we frameworku.

Ale nie ma róży bez kolców. Oto kilka mniej przyjemnych aspektów, które należy wziąć pod uwagę w momencie, gdy nastąpi już pierwszy 'efekt wow'.
Więc po kolei:
- cena, która jest dosyć spora, bo liczona per programista
-  problemy z instalacją w środowisku sharepoint - zapewne będzie to temat jednego z przyszłych wpisów. Generalnie udało nam się to zwalczyć własnymi siłami dla pojedyńczego serwera, za pomocą ręcznego instalowania paczek '.wsp' oraz ręcznych wpisów do web.config (automaty dostarczane przez producenta nie zadziałały, a wsparcie techniczne nie było nam w stanie pomóc), aczkolwiek syt. 'farmy serwerów', w której mamy dostęp do pliku web.config tylko jednego serwera nadal jest dla nas problematyczna.
- na słabszych sprzętowo maszynach,  obciążenie procesora/pamięci ram powodowało randomowe błędy krytyczne visual studio powodujące jego zamknięcie w trybie awaryjnym, w momencie włączania debuggera. O dziwo, problem ten występował tylko i wyłącznie dla aplikacji typu sharepoint.
- takie sobie wsparcie techniczne, które stara się pomóc, jednak z własnego doświadczenia wiem, że iż mimo, że jest całkiem miłe, to działa średnio sprawnie.


Generalnie temat warty rozważenia, aczkolwiek w przypadku firm typowo sharepointowych mocno wątpliwy, z uwagi na dodatkowe, mało znane producentowi problemy związane z developowaniem tych kontrolek w środowisku sharepoint.

niedziela, 9 czerwca 2013

Kilka wersji biblioteki jQuery na tej samej stronie

jQuery jest bardzo fajną i przydatną biblioteką javascriptową. Standardowo posiada jednak pewną wadę. W momencie, gdy kilka komponentów umieszczonych na stronie próbuje wczytać swoje biblioteki jQuery, wyrzuca dziwne błędy (jQuery przestaje działać częściowo lub w całości). Jest to związane z faktem, że system nie wie, do której konkretnej biblioteki ma się odwołać poprzez znacznik '$'. Jak uniknąć błędów, związanych z faktem, że na stronie może być umieszczony jeden lub kilka niezależnych komponentów, a każdy z nich niezależnie wymaga do działania biblioteki jQuery opisałem w jednym z poprzednich wpisów na blogu.

Życie jednak pokazuje, że czasami jesteśmy zmuszeni do wykorzystania na jednej stronie asp.net kilku bibliotek jQuery w różnej wersji biblioteki. Np. do 95% syt. chcemy wykorzystywać bibliotekę w wersji "stabilnej', natomiast do 5% syt. chcemy wykorzystać najnowszą funkcję biblioteki dostępnej jedynie w niestabilnej wersji biblioteki. Na szczęście biblioteka jQuery pozwala na zastosowanie takiego rozwiązania.

<script src="/_layouts/scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="/_layouts/scripts/jquery-ui-1.8.24.custom.min.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
var j182 = $.noConflict(true);$(document).ready(function(){                     
                        j182("#featured").tabs().tabs("rotate", 5000, true);
                        });//]]>
</script>


dodatkowo, po stronie kodu c# wpisujemy:

            if (!cs.IsClientScriptBlockRegistered("j182"))
                cs.RegisterClientScriptBlock(this.GetType(), "j182", @"var j182 = $.noConflict(true);", true);


W tym przypadku, mamy wczytane 2 biblioteki jQuery. Do pierwszej, w wersji 1.8.2 odwołujemy się normalnie, tj. poprzez znacznik '$', natomiast do drugiej, w wersji 1.8.24 poprzez znacznik przez nas zdefiniowany, tj. poprzez znacznik 'j182'.

czwartek, 14 marca 2013

Powershell a sharepoint

System Windows, podobnie jak system Linux posiada własny odpowiednik konsoli (terminala) administratora, w którym można uruchamiać polecenia oraz skrypty, za pomocą których administrator posiada pełną władzę nad systemem. W systemie Windows, interpreter poleceń wykorzystywany przez konsolę, oraz powiązany z nim język nazywa się Windows_PowerShell.

W teorii "Powershell" zapewnia administratorowi wszystkie dostępne opcje administracyjne, które może on wykonać zarówno z poziomu linii komend, jak i poprzez przygotowane wcześniej skrypty. Pełny i praktyczny poradnik, od czego warto zacząć podczas nauki obsługi "Powershella", można znaleźć jako odpowiedź na jedno z pytań, zamieszczonych na forum stackoverflow.com.

Podczas pisania skryptów, dobrze jest mieć "kolorowanie składni", co zapewni nam Powergui.

Skoro już mamy za sobą wstęp teoretyczny, narzędzie do kolorowania składni (aczkolwiek same skrypty zawsze możemy pisać w notatniku), oraz info, gdzie możemy zdobyć więcej praktycznych informacji o samym PowerShellu możemy przejść do analizowania interesującego nas zagadnienia czyli modyfikacja witryny sharepoint za pomocą skryptu powershell.
Utwórzmy wiec skrypt, który będzie pobierał 3 parametry (adres witryny, nazwę tabeli, nazwę pola), a nast. zmieńmy jedno z jego właściwości, np. wymagalność tego pola.

param
(
      [string] $portalURL = $(Throw "Missing 'portalURL' parameter"), #required parameter
      [string] $listName = $(Throw "Missing 'listName' parameter"), #required parameter
      [string] $fieldName = $(Throw "Missing 'fieldName' parameter") #required parameter
)

#komentarze pisze się z haszem na początku

$web = Get-SPWeb $portalURL;
$list = $web.Lists[$listName];
$field = $list.Fields.GetFieldByInternalName($fieldName);
[bool]$fvalue = $field.Required;

if ($fvalue) {
      $field.Required = 0;
      $field.Update();
      $list.Update();
} else {
      $field.Required = 1;
      $field.Update();
      $list.Update();
}
$web.Dispose();
 Jak widać, skrypt jest bardzo prosty. Na samym początku podajemy parametry, wykorzystywane przez skrypt  oraz określamy ich typ (sekcja 'param'). Nast. pobieramy SpWeba, listę SpList i pole SpField, po czym sprawdzamy jego wartość, a nast. zmieniamy jego wartości i wykonujemy update. Na sam koniec pobranego SPWeb'a musimy disposować. Dla programisty sharepoint ten kod wyda się dziwnie znajomy (tylko delikatnie nieco inna składnia).
To co jest WAŻNE, to aby zapisać skrypt w pliku tekstowym z rozszerzeniem *.ps1.

Wywołanie tego kodu, nast. poprzez: "Start->Microsoft Sharepoint 2010 Products -> Sharepoint 2010 Managment Shell"






A nast. w konsoli odpalamy utworzony przez nas skrypt wg. schematu: .\nazwaSkryptu.ps1 -parametrNr1 "ParametrNr1" -ParametrNr2 "ParametrNr2 -ParametrNr3 "ParametrNr3"

W przypadku większej ilości parametrów, zamiast podawać wszystkie parametry z konsoli, lepiej jest utworzyć osobny plik .csv z parametrami i umieścić go w tym samym katalogu co skrypt, a nast. wczytać jego zawartość wewnątrz skryptu.

P.S. Inny, bardziej zaawansowany przykład wykorzystujący power shell w kontekście sharepointa.






czwartek, 7 marca 2013

Build Version Increment

Jednym z bardzo prostych, a zarazem przydatnych pluginów do Visual Studio jest dostępny za darmo Build version increment. Plug in służy do automatycznego zwięszania nr. wersji znajdującego się w pliku AssemblyInfo.cs.

Ważne, aby w rozwiązaniach typu sharepoint inkrementować tylko i wyłącznie "AssemblyFileVersion" (natomiast "AssemblyVersion" musi pozostać nie zmienione). W przypadku normalnych rozwiązań asp.net wolno nam modyfikować oba parametry.

Po zainstalowaniu plug-ina, uruchamiamy go z opcji dostępnych w Visual Studio. Zakładka "Tools"->"Build Version Increment Settings", a nast. w popupie wybieramy interesujący nas projekt, w którym ustawiamy zasady inkrementowania. Osobiście preferuję ustawić opcję inkrementowania w oparciu o build, a numer rewizji w oparciu o "rok, nr. dnia w roku".
Przykładowe skonfigurowane opcje wyglądają tak:




piątek, 1 marca 2013

Pinterest / Blocksit layout

Jednym z najnowszych "krzyków mody", jest wyświetlanie newsów na stronie internetowej w "pseudo-tabelaryczny" sposób. Jest to sposób, który na pierwszy rzut oka przypomina nieco tabelę, ale nią nie jest, czyli dane ustawione są w kolumny, ale wysokość wierszy jest różna i zależna od ilości contentu (wysokość zdjęcia, ilość i długość komentarzy do zdjęcia itp.). Dodatkowo, resizując stronę (zmniejszając lub zwiększając okno przeglądarki) newsy się przestawiają w swojej "pseudo tabeli". Jako pierwsze (ale mogę się mylić), taki layout graficzny zastosowało na swojej stronie https://pinterest.com/, dlatego nazwałem ten layout "pinterest layout".

Teoretycznie, można by było zalogować się na stronę https://pinterest.com/ i spróbować przekopiować ich layout, ale takie rozwiązanie nie było by ani zbyt grzeczne, ani zbyt moralnie poprawne. Na szczęście dzięki www.google.com udało mi się znaleźć stronę, która zagregowała 'know how", czyli link do wtfdiary.com, na którym jest 6 'know how to do pinterest loyout'.

Mi osobiście najbardziej przypadł do gustu BlocksIt.js dlatego w dalszej części skupię się właśnie na tym rozwiązaniu. Jego zalety:
- to łatwość i prostota obsługi,
- ładny wygląd zewnętrzny,
- przystępny tutorial (zawierający 2 projekty demo)
- licencja  GNU GPL 2.0

Samo rozwiązanie nie jest niczym innym, jak wykorzystaniem biblioteki jQuery oraz dołączeniem do niego odpowiedniego jQuery plugin. Do tego dochodzą nam style CSS (ostylowanie naszego contentu) oraz kilka prostych skrytpów javascript (m.in. wykorzystywanych podczas resizowania strony).

To co potrzebujemy to pobrać najnowszą wersję biblioteki query oraz plik zip z demami blocksit

Moje rozwiązanie, które tutaj przedstawię, w dużej mierze opiera się na demie, które można pobrać z linku powyżej i jest to jedynie dostosowanie tego dema do aplikacji typu .net (asp.net / sharepoint).

Aby wykorzystać 'Blocksit' tworzymy nową stronę .aspx (może to być kontrolka .ascx), następnie do projektu dodajemy odpowiednie pliki:
- jquery-1.9.1.min (najnowsza wersja jquery w dniu 2013-03-01)
- blocksit.min (znajduje się w pliku z demem blocksit  - \blocksit-js\blocksit\demo2)
- style.css (znajduje się w pliku z demem blocksit - \blocksit-js\blocksit\demo2)
- zchpitblocksitdemo.js  (nasz plik ze skryptami, jakie będziemy utuchamiać na stronie)

Standardowo te skrypty były na stronie z demem, ale ja wolałem je przenieść do osobnego pliku .js i wyglądają one następująco:

$(document).ready(function () {
    //vendor script
    $('#header')
    .css({ 'top': -50 })
    .delay(1000)
    .animate({ 'top': 0 }, 800);

    $('#footer')
    .css({ 'bottom': -15 })
    .delay(1000)
    .animate({ 'bottom': 0 }, 800);

    //blocksit define
    $(window).load(function () {
        $('#container').BlocksIt({
            numOfCol: 5,
            offsetX: 8,
            offsetY: 8,
            blockElement: '.grid'
        });
    });

    //window resize
    var currentWidth = 1100;
    $(window).resize(function () {
        var winWidth = $(window).width();
        var conWidth;
        if (winWidth < 660) {
            conWidth = 440;
            col = 2
        } else if (winWidth < 880) {
            conWidth = 660;
            col = 3
        } else if (winWidth < 1100) {
            conWidth = 880;
            col = 4;
        } else {
            conWidth = 1100;
            col = 5;
        }

        if (conWidth != currentWidth) {
            currentWidth = conWidth;
            $('#container').width(conWidth);
            $('#container').BlocksIt({
                numOfCol: col,
                offsetX: 8,
                offsetY: 8
            });
        }
    });
});
 Ok. Przejdźmy zatem do omówienia najważniejszej części, czyli kodu strony .aspx / kontrolki .ascx:

Aby uzyskać ten layout, teoretycznie nie potrzebujemy żadnego 'code behind' i wystarczy nam czysty html, który docelowo powinien wyglądać podobnie jak na stronie z dema, czyli mniej więcej tak:

<link rel="stylesheet" href="/_layouts/style.css" type="text/css" />
<script src="/_layouts/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="/_layouts/blocksit.min.js" type="text/javascript"></script>
<script src="/_layouts//zchpitblocksitdemo.js" type="text/javascript"></script>
<div id="container">
    <div class="grid">
        <div class="imgholder">
            <img src="http://www.inwebson.com/demo/blocksit-js/demo2/images/img26.jpg" />
        </div>
        <strong>Bridge to Heaven</strong>
        <p>Where is the bridge lead to?</p>
        <div class="meta">by SigitEko</div>
    </div>
    <div class="grid">
        <div class="imgholder">
            <img src="http://www.inwebson.com/demo/blocksit-js/demo2/images/img15.jpg" />
        </div>
        <strong>Autumn</strong>
        <p>The fall of the tree...</p>
        <div class="meta">by Lars van de Goor</div>
    </div>
</div>
Aby jednak uzyskać, w pełni dynamicznie generowany przez nas layout, skorzystamy z kontrolki literala, czyli nasz kod html będzie wyglądał tak:

<link rel="stylesheet" href="/_layouts/style.css" type="text/css" />
<script src="/_layouts/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="/_layouts/blocksit.min.js" type="text/javascript"></script>
<script src="/_layouts//zchpitblocksitdemo.js" type="text/javascript"></script>

<div id="container">
    <asp:Literal runat="server" ID="ltrGrid" ></asp:Literal>
</div>
W tym przypadku, będziemy potrzebowali stworzyć 'code behind', który w najprostszym możliwym przypadku będzie wyglądał tak:

        protected void Page_Load(object sender, EventArgs e)
        {
            SetLiteralGrid();
        }
        private void SetLiteralGrid()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("<div class='grid'>");
            sb.AppendLine("<div class='imgholder'>");
            sb.AppendLine("<img src='http://www.inwebson.com/demo/blocksit-js/demo2/images/img27.jpg' />");
            sb.AppendLine("</div>");
            sb.AppendLine("<strong>Sunset Lake</strong>");
            sb.AppendLine("<p>A peaceful sunset view...</p>");
            sb.AppendLine("<div class='meta'>by j osborn</div>");
            sb.AppendLine("</div>");

            ltrGrid.Text = sb.ToString();
        }
 Oczywiście w realnych scenariuszach interesuje nas wypełnienie contentem pełnej strony (a nie tylko pojedyńczego newsa), ale wtedy w 'code behind' wystarczy zwyczajnie wcześniej pobrać potrzebne dane i wrzucić je do StringBuildera za pomocą pętli.



niedziela, 24 lutego 2013

SPMonitoredScope, czyli sprawdzanie wydajności w aplikacjach sharepoint

Tematem aktualnego wpisu jest sposób, na sprawdzenie wydajności naszej aplikacji sharepoint, a dokładniej czasu jaki jest potrzebny, aby wyświetlić naszą aplikację w przeglądarce internetowej. Ponieważ temat wydajności w sharpoint jest bardzo obszerny, a z problemem zwiększania wydajności aplikacji sharepoint spotkał się niemal każdy doświadczony programista, dobrze jest mieć jakieś narzędzie, które zautomatyzuje proces sprawdzania wyników. Narzędzie, dzięki któremu będziemy wiedzieli, jaki dokładnie wpływ na wydajność mają zmiany w kodzie,  które wprowadzamy podczas procesu optymalizacji.

Tutaj z pomocą przychodzi nam SPMonitoredScope, które jest darmowym narzędziem służącym do lokalizacji wydajnościowego "wąskiego gardła". Jedynym ograniczeniem, jakie posiada SPMonitoredScope są rozwiązania typu "sandbox" ("piaskownica"), w których SPMonitoredScope nie działa.

Sposób wykorzystania SPMonitoredScope jest bardzo prosty:
Najpierw odpalamy konsolę (Start -> wyszukaj programy -> cmd.exe). W konsoli natomiast uruchamiamy program stsadm (ja uruchamiałem go z roota, do którego przechodzimy za pomocą komendy "cd..").  Dostępne komendy, możemy znaleźć na MSDN pod tym linkiem.  Osobiście preferuję opcję "on demand", czyli:

stsadm -o setproperty -pn developer-dashboard -pv ondemand 
Wyłączenie SPMonitoredScope następuje poprzez wpisanie w konsoli:

stsadm -o setproperty -pn developer-dashboard -pv off

Sprawdzanie konkretnych, wybranych partii kodu, pod kątem wydajności następuje, poprzez wykonanie naszego kodu wewnątrz "using-a".

using (new SPMonitoredScope("CallMethod1 Monitored Scope"))
{
    //TODO: tutaj będzie kod, który chcemy przetestować.
}
 
Wyniki sprawdzamy w przeglądarce, w nowej zakładce, która się pojawi, gdy tylko będziemy mieli aktywny SPMonitoredScope. Co do samych wyników, to dobrze jest stronę załadować przynajmniej kilka razy i nast. wyciągnąć średnią.

P.S. Link do bloga Tobiasa Zimmergrena, którego wpis stał stał się inspiracją dla mojego wpisu.