27/11/2010

Reporting Services i schowane etykiety

Home

Poniższy rysunek zawiera fragment wykresu wygenerowanego przez SQL Server Reporting Services. Wykres ten przedstawia wartość pewnej miary (oś OY) dla różnych kategorii (oś OX). Mniejsza o jaką miarę i kategorię chodzi. Problem polega na tym, że etykiety posiadają tylko niektóre słupki, a nie wszystkie co czyni wykres bezużytecznym. Nie sposób bowiem wydedukować jakie kategorie zostały pokazane np.: pomiędzy JNZ i OR.



Nie zastanawiając się długo postanowiłem, więc dodać etykiety dla wszystkich słupków. Wbrew pozorom znalezienie rozwiązania zajęło mi trochę czasu, a rozwiązanie okazało się mało intuicyjne. Zacząłem od przejrzeniu wszystkich okienek kreatora wykresu i wypróbowaniu różnych przełączników. Niestety bez sukcesu. Następnie zauważyłem, że okno Properties dla osi OX zawiera dużo, dużo więcej właściwości niż jest udostępnione w kreatorze, żeby nie skłamać dobre kilkadziesiąt. Trochę już zniechęcony postanowiłem je przejrzeć i po chwili znalazłem grupę właściwości o nazwach zaczynających się od Label, a wśród nich właściwość LabelInterval ustawioną na wartość Auto.



Zgodnie z nazwą właściwość ta powinna określać krok co jaki będą wyświetlane etykiety. Opis właściwości (Labels interval size) to masło maślane ale co szkodzi sprawdzić. Zamiast Auto wpisałem więc 1. Okazało się to strzałem w dziesiątkę. Po tej niewielkiej zmianie wykres prezentuje się jak poniżej:


25/11/2010

Czemu VB.NET jest be?

Home

Z językiem VB.NET da się pracować, co z powodzeniem czynię od blisko roku, ale niektóre rzeczy doprowadzają mnie do szału. Aby wyjaśnic o co chodzi posłużę się bardzo, bardzo prostym interfejsem pokazanym poniżej:
Public Interface IFun
  Function Fun() As Integer
  Function SuperFun() As Integer
End Interface
Implementacja funkcji Fun oraz SuperFun jest trywialna i wyglądają jak poniżej:
Public Function Fun() As Integer
  Return 0
End Function

Public Function SuperFun() As Integer
  Return 1
End Function
Jeszcze kod, który korzysta z tej implementacji:
Sub Main()
  Dim fun As Fun = New Fun()
  Dim ifun As IFun = fun

  Console.WriteLine(fun.Fun() = ifun.Fun())
  Console.WriteLine(fun.SuperFun() = ifun.SuperFun())
  Console.WriteLine(fun.Fun() = ifun.SuperFun())
  Console.WriteLine(fun.SuperFun() = ifun.Fun())
End Sub
A na koniec pytanie, jaki wynik zostanie wypisany na ekan? Założę się, że nikt się nie zawacha i odpowie:
True
True
False
False
Taki wynik jest oczywiście logiczny i prawidłowy ale nie zawsze, w przypadku VB.NET można uzyskać również taki wynik:
False
False
True
True
Nie trzeba do tego stosować żadnych sztuczek, wystarczy zwykła pomyłka. Pokazując implementację metod Fun oraz SuperFun celowo pominąłem słowo kluczowe Implements, które określa jaki element intefejsu implementuje dana metoda. Kod klasy powinien wyglądać tak:
Public Class Fun
  Implements IFun

  Public Function Fun() As Integer Implements IFun.Fun
    Return 0
  End Function

  Public Function SuperFun() As Integer Implements IFun.SuperFun
    Return 1
  End Function
End Class
Niestety ponieważ metody Fun oraz SuperFun mają takie same sygnatury to nic nie stoi na przeszkodzie aby zamienić miejscami Implements IFun.Fun z Implements IFun.SuperFun i otrzymać coś takiego:
Public Class Fun
  Implements IFun

  Public Function Fun() As Integer Implements IFun.SuperFun
    Return 0
  End Function

  Public Function SuperFun() As Integer Implements IFun.Fun
    Return 1
  End Function
End Class
Mały, wkurzajacy i bardzo trudny do wykrycia błąd wynikający z cech języka VB.NET.

19/11/2010

Moda na chmurę

Home

To, że konferencja MTS 2010 odbyła się w dużym stopniu pod znakiem chmury obliczeniowej nie dziwi mnie. Nie dziwi mnie również, że prasa branżowa, portale społecznościowe, blogi i fora są pełne artykułów i postów na ten temat. Cloud computing to przecież relatywnie nowe i bardzo ciekawe ze względów technologicznych zagadnienie, również dla mnie.

Jestem natomiast zaskoczony, że tematyka chmury obliczeniowej zaczęła bardzo szybko wpływać szerokim nurtem do prasy nie branżowej. W czasie ostatniej wizyty w salonie prasowym w jednym z magazynów przeznaczonych dla menadżerów, którego tytułu niestety nie pamiętam, zobaczyłem artykuł zachwalający zalety chmury. Zaś w magazynie Forbes znalazłem cały, obszerny dodatek poświęcony tylko chmurze! Z ciekawości sprawdziłem czy tematyka chmury była poruszana na portalach takich jak onet.pl czy rp.pl i znalazłem kilka artykułów. Z innych przykładów, koleżanka, która pracuje w instytucji finansowej, powiedziała mi, że dyrektor działu IT zapowiada wykorzystanie tej technologii. Od kolegi z pracy dowiedziałem się natomiast, że jego promotor, który do tej pory nie przywiązywał uwagi do nowinek, stwierdził, że chmura to coś ciekawego.

Chmura bardzo szybko staje się albo już stała się modna, słyszy się o niej prawie wszędzie, a przede wszystkim budzi zainteresowanie biznesu. Z jednej strony niesie to z sobą szanse rozwoju firm, które zainwestują w chmurę oraz kontraktów dla firm IT. Z drugiej strony stare przysłowie mówi, że co nagle to po diable. Nie budzi natomiast wątpliwości fakt, że działy marketingowe dostawców rozwiązań typu cloud wykonały kawał dobrej roboty.

17/11/2010

100 postów

Home

Niby 100 to liczba jak każda inna ale jednak ponad 100 opublikowanych postów skłoniło mnie do spojrzenia wstecz i napisania krótkiego podsumowania. Należy zacząć od tego, że napisanie takiej liczby postów zajęło mi 2 lata co daje średnio 4 posty w miesiącu. Mało to czy dużo? Dla mnie w sam raz. Były okresy, w których publikowałem więcej i takie, w których pojawiał się jeden post w miesiącu. Poruszałem różne tematy, głównie związane z platformą .NET i nowoczesnymi technologiami ale pojawiły się również posty związane z grami komputerowymi, mini recenzje sztuk teatralnych czy na temat inicjatywy Powrót do Ojczyzny. Zawsze starałem się aby to co piszę było dla innych w jakiś sposób wartościowe. Nie mi to oceniać ale wierzę, że mi się udało.

Co zrobiłem w ciągu 2 lat?

W tym czasie blog ewaluował i zmieniał się, domyślny szablon dostosowałem do swoich potrzeb i gustu, dodałem podświetlanie składni przy pomocy syntaxhighlighter'a, chmurę etykiet, QR kod z zakodowanym moim adresem e-mail, sekcję Aktualnie czytam, stopkę z informacją o prawach autorskich, licznik subskrypcji ... by w końcu osiągnąć obecną, odpowiadającą mi w prawie 100% formę. Nauczyłem się jak pisać i redagować posty oraz, że każdy post przed opublikowaniem należy odłożyć i wrócić do niego za kilka godzin lub najlepiej następnego dnia w celu ponownego sprawdzenia. Nieoceniony jest, że kiedy wpiszę w Google swoje imię i nazwisko to mój blog pokazywany jest na jednym z pierwszych miejsc. Moje wpisy pojawiają się wśród pierwszej 10 wyników po wpisaniu takich haseł jak: IntelliTrace, blog programowanie czy visual studio blog (stan na moment pisania tego postu). Linki to mojego bloga można również znaleźć w serwisach dotnetmaniak, dotnetblogs czy dotnetnews. Nie jestem już, więc anonimowy w sieci, a co najważniejsze pokazałem się z dobrej strony, a to było jednym z moich celów kiedy zaczynałem blogowanie.

Co dalej?

Co tu ukrywać blogowanie spodobało mi się. W przyszłości chciałbym przynajmniej utrzymać, a najlepiej zwiększyć średnią 4 postów w miesiącu, oczywiście bez obniżenia poziomu. Będę również starał się zdobyć więcej czytelników i pobudzić ich do komentowania. Po głowie chodzą mi również takie pomysły jak przejście z bloggera na platformę WordPress czy artykuły dwujęzyczne (Pl/En).

Jeśli ktoś z Was ma dla mnie jakieś rady lub uwagi, coś mu się w tym blogu nie podoba albo odwrotnie coś mu przypadło do gustu, a może chciałby więcej lub mniej wpisów na jakiś temat i powinny być dłuższe lub krótsze... to z przyjemnością wysłucham wszystkich głosów.

09/11/2010

Poznaj swój program

Home

Tematykę IntelliTrace poruszałem już kilkukrotnie. Dzisiaj chciałbym powrócić do zagadnienia opisanego w poście Logi IntelliTrace bez tajemnic czyli analizy logu przy pomocy IntelliTrace API. Tym razem napiszę w jaki sposób dostać się do informacji o tym kiedy została wywołana jakaś metoda, jaki wynik zwróciła i jakie były parametry wywołania. Informacje te są prezentowane w oknie Calls View w Visual Studio 2010 ale można je analizować w ograniczonym stopniu. Poniższe informacje przydadzą się każdemu kto będzie chciał na przykład załadować te dane do bazy danych w celu później analizy, na przykład przy pomocy algorytmów odkrywania wiedzy (data mining).

Zacznijmy od wzorca kodu, który posłuży nam do odczytania pliku z logiem:
using (IntelliTraceFile file = new IntelliTraceFile(pathToIntelliTraceLog))
{
  //Kolekcja procesów będzie miała tylko jedną pozycję
  foreach (IntelliTraceProcess process in traceFile.Processes)
  {
    //Przetworzenie kolejnych wątków
    foreach (IntelliTraceThread thread in process.Threads)
    {
      //Tworzymy strumień ze zdarzeniami. Każde zdarzenie odpowiada np.: wywołaniu metody
      Chain chain = thread.CreateThreadChain<ThreadChain>();
  
      EventToken eventToken = chain.FirstValidToken;
      //Przetwarzamy zdarzenie po zdarzeniu
      while (eventToken != chain.AfterLastToken)
      {
        //Pobranie zdarzenia
        IntelliTraceEvent ev = chain.GetEvent(eventToken);

        //To zdarzenie reprezentujące wywołanie metody
        if(ev is MethodEnterEvent)
          ProcessMethodEnterEvent(ev);
        //To zdarzenie reprezentujące zakończenie wywołania metody
        else if(ev is MethodExitEvent)
          ProcessMethodExitEvent(ev);
          
        eventToken = chain.GetNextToken(eventToken);
      }
    }
  }
}
Powyższy kod zawiera dużo komentarzy dlatego nie powinno być trudności z jego zrozumieniem. Chciałbym zwrócić uwagę tylko na jedną rzecz. Lista zdarzeń jakie możemy obsłużyć zawiera znacznie więcej pozycji niż tylko dwie pokazane powyżej (MethodEnterEvent, MethodExitEvent). Niestety ale nie ma dobrej dokumentacji z pełną listą jaki "łańcuch zdarzeń" jakie zdarzenia udostępnia. Pozostaje droga eksperymentalna oraz przyjrzenie się projektowi iTraceReader, o którym już pisałem w poście Logi IntelliTrace bez tajemnic.

Zobaczmy, więc jak wyglądają metody ProcessMethodEnterEvent oraz ProcessMethodExitEvent. Na samym początku należy zamienić zdarzenia MethodEnterEvent oraz MethodExitEvent, które zawierają tylko suchy ciąg bajtów na bardziej przyjazne ResolvedMethodEnterEvent oraz ResolvedMethodExitEvent, z których łatwo wyciągniemy interesujące nas informacje.
private void ProcessMethodEnterEvent(IntelliTraceEvent ev)
{
  ResolvedMethodEnterEvent methodEnterEvent = new ResolvedMethodEnterEvent(CurrentProcess, ev as MethodEnterEvent);
  //...
}
Klasy ResolvedMethodEnterEvent oraz ResolvedMethodExitEvent zawierają właściwość Method, która zwraca obiekt klasy ResolvedMethod. Klasa ta reprezentuje wywołaną metodę i udostępnia następujące bardzo intuicyjne właściwości:
  • ContainingTypeName - Pełna nazwa typu (razem z przestrzenią nazw) w ramach, którego metoda została zdefiniowana.
  • MethodName - Nazwa metody.
  • ParameterNames - Nazwy (ale nie wartości) parametrów.
  • ParameterTypeNames - Pełne nazwy typów parametrów.
  • ReturnTypeName - Pełna nazwa typu (ale nie wartość) zwracanego przez metodę.
Teraz przejdźmy do odczytania parametrów przekazanych do metody przy jej wywołaniu. Do tego celu posłuży nam metoda:

IList<IDataElement> ResolvedMethodEnterEvent.GetParameters()

W celu reprezentowania różnych bytów IntelliTrace API udostępnia interfejs o nazwie IDataElement. IDataElement może reprezentować typy proste i referencyjne. W przypadku typu referencyjnego IDataElement może zawierać elementy podrzędne reprezentujące składowe obiektu, które również będą reprezentowane przez IDataElement. Napisałem może, a nie musi ponieważ IntelliTrace analizuje tylko obiekty pierwszego poziomu. Czyli jeśli parametr jakiejś metody to obiekt klasy A, który zawiera składowe typu string, int oraz wskazanie na obiekt klasy B to IntelliTrace zapisze w logu wartości wszystkich składowych typów prostych obiektu klasy A ale już nie obiektu klasy B. Na temat obiektu klasy B dowiemy się tylko tyle, że jest. Poniżej zamieszczam opis interfejsu IDataElement. Zaznaczam jednak, że tworząc ten opis bazowałem na doświadczeniu i przeprowadzonych eksperymentach dlatego może on zawierać nieścisłości lub błędy:
  • HasChildren - true jeśli mamy do czynienia z typem referencyjnym i jest to obiekt pierwszego poziomu, false w przypadku typów prostych i obiektów zagnieżdżonych.
  • Name - Nazwa parametru, nazwa składowej obiektu, '[Return value]' dla wartości zwracanej przez metodę, this lub base.
  • TypeName - Pełna nazwa typu reprezentowanego bytu.
  • Value - W przypadku typów prostych właściwa wartość, a w przypadku typów referencyjnych nazwę typu. Jeśli wartość nie została zapisana przez IntelliTrace otrzymamy wynik 'unknown'.
  • GetChildren - Metoda, którą możemy wywołać jeśli właściwość HasChildren jest równa true. Metoda ta zwraca elementy podrzędne w stosunku do bieżącego.
Warto również wiedzieć o poniższej metodzie, która służy do pobrania wyniku zwróconego przez metodę:

IDataElement ResolvedMethodExitEvent.GetReturnValue()

Znacznie rzadziej będą nas interesowały parametry typu out, do których uzyskamy dostęp przy pomocy poniżej metody. Niestety ale wygląda na to, że metoda ta zawiera jakiś błąd. Próbowałem wywołać ją kilkukrotnie dla rożnych metod z parametrem out typu string. Za każdym razem kończyło się to błędem. Raz był to wyjątek ArgumentOutOfRangeException innym razem ApplicationException.

IList<IDataElement> ResolvedMethodExitEvent.GetOutputs()

Podsumowując pomimo ograniczeń IntelliTrace API zachęcam do zabawy z logami.