18/06/2009

Xslt jako język programowania

Home

Ostatnio sporo czasu poświęcam poznawaniu nowych narzędzi w Visual Studio 2010 czyli pożytecznej zabawie. Przy tej okazji uczę się również czasami czegoś na temat starszych wersji tego środowiska. Na przykład niedawno zajmowałem się narzędziami wspierającymi pracę z szeroko pojętym Xml'em, a w szczególności z transformacjami Xsl. Obok rzeczy wręcz oczywistych takich jak podświetlenie składni, podpowiadanie - IntelliSense znajdziemy również: profiler, debugger czy podgląd wyniku działania transformacji. Co ciekawe narzędzia te, oprócz profilera, znajdują się również w Visual Studio 2005/2008. Muszę przyznać, że do tej pory nie zdawałem sobie sprawy z tego, że Visual Studio traktuje Xslt jako "normalny" język programowania. Co tu dużo mówić, człowiek uczy się całe życie.

Dla tych co żyli w niewiedzy tak jak ja kilka zdań na ten temat. Zaczynamy od otworzenia pliku z definicją transformacji (z rozszerzeniem *.xslt) albo od dodania go do projektu. We właściwościach otwartego dokumentu (zakładka Properties) mamy do wypełnienia dwa pola: Input oraz Output. W pierwszym wskazujemy dokument Xml do przekształcenia, a w drugim plik wynikowy.



Analogicznie można zacząć od otworzenia pliku Xml. W tym przypadku na zakładce Properties będziemy mieli do wypełninia pola: Stylesheet oraz Output. W pierwszym wskazujemy plik z transformacją, a znaczenie drugiego jest takie same jak wcześniej.

W momencie kiedy mamy otworzony plik z transformacją albo plik Xml na pasku menu pojawi się element o nazwie XML.



Z tego menu może po pierwsze wybrać polecenie Show XSLT Output, które odpali transformację i pokaże nam jej wynik. Dużo ciekawsze jest jednak polecenie Debug XSLT, które umożliwia śledzenie wykonania transformacji.

Pułapki umieszczamy w kodzie transformacji dokładnie w taki sam sposób jak w kodzie programu napisanego w C#. Co więcej pułapki możemy też postawić w dokumencie Xml. Funkcji tej można użyć kiedy interesuje nas ściśle określony węzeł w dokumencie i chcemy aby debugger zatrzymał się kiedy będzie przetwarzany. Bardzo przydatne jest to, że na bieżąco możemy obserwować jak generowany jest plik wynikowy. Kod transformacji lub dokument Xml możemy teoretycznie modyfikować w czasie działania transformacji ale nie odniesie to żadnych skutków.



W Visual Studio 2010 pojawiła się jeszcze możliwość profilowania transformacji (w menu XML dodane zostało polecenie Profile XSLT). Możemy sprawdzić, wykonanie której część kodu transformacji zajmuje najwięcej czasu itd. Okno z raportem z wynikami profilowania zostało przedstawione poniżej:


04/06/2009

Bardzo użyteczne narzędzie do pracy z WMI

Home

Przeglądając dzisiaj fora internetowa, dotyczące platformy .NET, w odpowiedzi na jedno z zadanych pytań znalazłem wzmiankę o bardzo użytecznym narzędziu WMI Code Creator v1.0. Narzędzie to pozwala na wygenerowanie kodu używającego WMI (ang. Windows Management Instrumentation) do wykonywania różnego rodzaju zadań zarządzania: odczytywanie danych, oczekiwanie na zdarzenia WMI czy wywoływanie metod z klas WMI.

WMI nie jest za pewne narzędziem używanym w codziennej pracy ale mogącym się czasem przydać. Przy pomocy tej technologii możemy dobrać się do szczegółowych inforamacji na temat BIOS'u, procesora, dysków i innych urządzeń, procesów, usług oraz najróżniejszych ustawień systemu operacyjnego. WMI posługuje się dobrze znanymi pojęciami takimi jak: przestrzenie nazw, klasy, metody, zdarzenia i właściwości. Przestrzenie nazw zawierają klasy dotyczące poszczególnych obszarów zarządzania. Klasy modelują różne byty w tych obszarach. Właściwości tych klas to różne parametry konfiguracyjne. Na przykład dla klasy modelującej procesor możemy odczytać jego rodzinę, producenta czy liczbę rdzeni. Dla klasy modelującej proces została zdefiniowana metoda pozwalająca go zamknąć. Przykładem zdarzenia na jakie można oczekiwać jest natomiast zmiana statusu usługi.

Z poziomu platformy .NET do komunikacji z WMI służą klasy z przestrzeni nazw System.Management. Ich użycie nie jest bardzo skomplikowane, główna trudność polega na mnogości przestrzeni nazw i klas WMI. Nie sposób tego spamiętać. Tutaj z pomocą przychodzi wspomniane narzędzie. Przy jego pomocy możemy wybrać interesującą nas przestrzeń, potem klasę i jej właściwości, a następnie wygenerować kod w jednym z trzech języków: C#, Visual Basic .NET, Visual Basic Script, który odczyta parametry jakie wybraliśmy, wywoła metodę lub będzie oczekiwał na zdarzenia WMI. Co bardzo przydatne WMI Code Creator v1.0 pozwala podejrzeć wartości wybranych właściwości.

02/06/2009

Problemy z instalatorem

Home

A problem has been encountered while loading the setup components. Canceling setup

Komunikat ten, objaśniający bardzo dokładnie przyczynę błędu ;), napotkałem próbując doinstalować do Visual Studio 2008 Team System komponenty związane z obsługą języka C++. Rozwiązanie problemu okazało się trywialne ale dojście do niego zajęło mi trochę czasu.

Rozwiązywanie problemu rozpocząłem od sprawdzenia czy w katalogu z plikami instalacyjnymi znajdują się inne pliki z setup w nazwie lub podobne i czy można je uruchomić. Kiedy to nie pomogło skopiowałem cały katalog z instalatorem i potrzebnymi plikami na dysk lokalny przyjmując, że problem może wynikać z tego, że uruchamiam go z dysku zdalnego. Niestety ale to również nie pomogło.

Zacząłem szukać pomocy u pana Google. Natrafiłem na forum, na którym radzono aby po prostu odinstalować środowisko i wszystkie jego komponenty, a następnie zainstalować je jeszcze raz. Pewnie by podziałało ale nie chciałem poświęcać cennego czasu na ponowne instalowanie wszystkiego czego potrzebuję.

Po dalszych poszukiwaniach znalazłem wskazówkę mówiącą abym poszukał w katalogach tymczasowych logów instalatora i zobaczył co się w nich znajduje. Rada była o tyle mało użyteczna, że nie zawierała informacji gdzie dokładnie szukać plików i jak się nazywają. Uruchomiłem więc Process Monitor i zacząłem przeglądać jakie pliki otwiera instalator VS. W moim przypadku nazywały się: dd_install_vs_vstdcore_90.txt oraz dd_error_vs_vstdcore_90.txt i znajdowały się w katalogu:
C:\Documents and Settings\username\Local Settings\Temp
W jednym z plików znalazłem wpisy zawierające tekst ERRORLOG EVENT, coś w tym rodzaju:
[06/02/09,12:25:45] setup.exe: ***ERRORLOG EVENT*** : ISetupModule::SetManager() failed in ISetupManager::LoadSetupObjectGuid() : vs_setup.dll
Nie zastanawiając się długo wrzuciłem treść loga do Googla i jak to zwykle otrzymałem dużoooooooo wyników. Jedna z pierwszych stron, zresztą forum MSDN, dotyczyła VS 2005 ale wyglądała obiecująco. Wyczytałem na niej, że problem ustępuje po wyłączeniu antywirusa, a dokładniej programu firmy Kaspersky. Korzystam co prawdy z produktu konkurencji ale stwierdziłem, że nie zaszkodzi spróbować. Niestety ale i to rozwiązanie okazało się chybione. Kiedy już prawie straciłem nadzieję kilka pozycji niżej na liście wyników znalazłem ten post. Żeby nie przedłużać rozwiązanie problemu to:

W przypadku Visual Studio 2008 z zainstalowanym service pack'iem pierwszym (nie wiem jak z kolejnymi) instalator należy uruchamiać z poziomu okna Add or Remove Programs w panelu sterowania.

Data Binding i dobre praktyki programistyczne

Home

The data source for GridView with id 'GridView1' did not have any properties or attributes from which to generate columns. Ensure that your data source has content.

Czy spotkaliście się z takim błędem pomimo, że byliście pewni, że poprawnie zasilacie kontrolkę lub powiązane z nią źródło danych? Jeśli tak to problem był związany z użytymi strukturami danych. Przykładowy kod, który spowoduje powyższy błąd został przedstawiony poniżej. Zacznijmy od prostej klasy, którą chcemy zaprezentować na kontrolce GridView.
public class Data
{
  public int Id;
  public string Name;
}
Fragment kodu strony:
...
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
...
Kod zasilający kontrolkę jest równie prosty, dla uproszczenie nie korzystam ze źródła danych:
...
this.GridView1.DataSource = new Data[] { new Data { Id = 1, Name = "1" }, new Data { Id = 2, Name = "2" } };
this.GridView1.DataBind();
...
Uważny czytelnik mógł zauważyć, że w klasie Data użyłem publicznych pól składowych zamiast właściwości. I tu leży pies pogrzebany. Pola składowe klasy nie są automatycznie wykrywane i obsługiwane przy dowiązywaniu kontrolki (ang. binding). Innymi słowy pola trzeba opakować we właściwości. Nie wiem czy to przeoczenie w implementacji czy celowe działanie (biorąc pod uwagę treść komunikatu to drugie) ale w każdym razie ograniczenie to wspiera dobre praktyki programistyczne. Poprawny kod klasy Data powinien wyglądać tak:
public class Data
{
  public int Id { get; set; };
  public string Name { get; set; };
}

25/05/2009

Konkurs Code Camp 2009 - podsumowanie

Home

Na podsumowanie konferencji Code Camp 2009 w Warszawie z mojej perspektywy nadejdzie jeszcze czas. Najpierw chciałbym napisać o konkursie, który udało mi się zorganizować przy tej okazji. W skrócie konkurs składał się z dwóch etapów. Pierwszy etap (tzw. konkurs skojarzeniowy) odbył się w tygodniu poprzedzającym konferencję i polegał na odgadnięciu nazwy miejsca (kraju, miasta, wyspy itd.) na podstawie zdjęć, obrazków czy też opisu słownego. Wszystkie te miejsca miały tą wspólną cechę, że ich nazwy zostały użyte jako nazwy kodowe różnych produktów firmy Microsoft. Drugi etap, konkurs kartkowy, odbył się w czasie konferencji i polegał na odpowiedzeniu na 5 testowych pytań. Odpowiadając na pytanie nie można było korzystać z komputera, Internetu czyli trzeba było liczyć tylko na własną głowę.

Jak wyszło? Mówiąc szczerze nie jest do końca zadowolony. Frekwencja co tu dużo mówić nie dopisała. W konkursie wzięło udział tylko 6 osób. Chociaż z tego co dowiedziałem się od bardziej doświadczonych kolegów to i tak całkiem dobry wynik :)

Jeśli chodzi o konkurs skojarzeniowy to okazał się on dość łatwy i generalnie uczestnicy nie mieli problemów z odpowiedzeniem na pytania. Z konkursem kartkowym było już gorzej, poprawnych odpowiedzi było zdecydowanie mniej. Wydaje mi się, że było to spowodowane dwoma czynnikami. Po pierwsze pytania mogły być zbyt szczegółowe ale ja nie jestem tutaj obiektywny. Po drugie, konkurs był przewidziany na raptem 10 - 15 minut. Najwyraźniej nie udało mi się dostosować poziomu pytań do tak krótkiego czasu. Muszę o tym pamiętać i następnym razem przetestować pytania na znacznie większej grupie ludzi niż to uczyniłem.

Poniżej zamieszczam pytania i odpowiedzi do obu konkursów:

Konkurs skojarzeniowy


Odpowiedzi

  1. Dublin - Opis
  2. Hawaii - Visual Studio
  3. Astoria - ADO.NET Data Services
  4. Kilimanjaro - Sql Server 2010/Dynamics CRM 4.0
  5. Orleans - Opis
  6. Geneva - Opis
  7. Paris - Opis
  8. Ibiza - Sync Framework
  9. Oslo - Opis
  10. Quebec - Windows Embeded 2010
Do trzeciego pytani wkradł się błąd. Pytałem w nim o miasto na wschodnim wybrzeżu podczas gdy chodziło o zachodni brzeg USA. Z tego powodu zaliczałem również inne odpowiedzi na przykład Boston czyli Visual Studio 97.

Konkurs kartkowy

1. Mamy definicje dwóch klas jak poniżej:
class Base
{
   public virtual void Fun(int x)
   {
      Console.WriteLine("Base.Fun(int x)");
   }
}

class Derived : Base
{
   public override void Fun(int x)
   {
      Console.WriteLine("Derived.Fun(int x)");
   }

   public void Fun(object o)
   {
      Console.WriteLine("Derived.Fun(object o)");
   }
}
Co wypisze na ekran podany kod:
Derived d = new Derived();
d.Fun(1);
  1. Base.Fun(int x)
  2. Derived.Fun(int x)
  3. Derived.Fun(object o)
  4. Wywołanie metody spowoduje wyjątek
2.
Nullable<int> nullable = new Nullable<int>();
Type t = nullable.GetType();
Jaki rodzaj wyjątku zostanie rzucony po uruchomieniu tego kodu?
  1. Żaden
  2. InvalidOperationException
  3. NullReferenceExcpetion
  4. IndexOutOfRangeException
  5. ArgumentNullException
3. Załóżmy, że mamy zdefiniowaną zmienną o nazwie variable. Kiedy poniższy kod nie spowoduje rzucenia wyjątku:
variable = null;
variable.ToString();
4. Jaki będzie wynik wykonania poniższego kodu:
string s1 = new String(new char[] { 'a' });
string s2 = new String(new char[] { 'a' });
bool result = Object.ReferenceEquals(s1, s2);
Console.Write(result);

s1 = new String(new char[0]);
s2 = new String(new char[0]);
result = Object.ReferenceEquals(s1, s2);
Console.Write(result);

s1 = "Ala ma kota";
s2 = "Ala ma" + " kota";
result = Object.ReferenceEquals(s1, s2);
Console.Write(result);

s1 = "Ala ma kota";
string temp = "ma";
s2 = "Ala " + temp  + " kota";
result = Object.ReferenceEquals(s1, s2);
Console.Write(result);
  1. True, False, True, Talse
  2. False, False, True, False
  3. False, True, True, False
  4. False, False, False, False
  5. True, True, True, False
5. Jaki będzie wynik wykonania poniższego kodu:
delegate void Printer();
...
List printers = new List();
for (int i = 0; i < 4; i++)
{
  if (i % 2 == 0)
  {
      printers.Add(delegate { Console.Write(i); });
  }
  else
  {
     int j = i;
     printers.Add(delegate { Console.Write(j); });
  }
}

foreach (Printer printer in printers)
   printer();
  1. 0, 1, 2, 3
  2. 4, 4, 4, 4
  3. 4, 1, 4, 3
  4. 3, 2, 1, 0
  5. Inny

Odpowiedzi

  1. C - Derived.Fun(object o);

    W przypadku wywołania derived.Fun(1) zostanie wywołana metoda Derived.Foo(object). Metody zdefiniowane bezpośrednio na poziomie klasy wywołującej mają zawsze priorytet nad metodami zdefiniowanymi na poziomie klasy bazowej nawet jeżeli zostały przedefiniowane w klasie pochodnej. Jest tak ponieważ przy szukaniu metody najlepiej pasującej do wywołaniu, spośród wszystkich metod kandydujących odrzucane są metody zdefiniowane poza typem najbardziej wydziedziczonym. W wyniku tego kroku ze zbioru mogą zostać usunięte metody wirtualne.

  2. C - NullReferenceException

    Uruchomienie tego kod zakończy się rzuceniem wyjątku NullReferenceException w linijce z wywołaniem GetType. Typ Nullable<T> dostarcza własną implementacja ToString oraz GetHashCode ale nie GetType. Wywołanie GetType prowadzi więc do przekształcenia wartości Nullable<int> w referencje do obiektu (opakowywanie), a ponieważ w tym przypadku Nullable.HasValue jest równe false na stos odkładany jest null.

  3. Jeśli variable jest typem Nullable<T>

  4. C - False, True – bug?, True – optymalizacja kompilatora, False

  5. C - Domknięcie - Jak to działa?