09/11/2009

Jeszcze o rysowaniu wykresów

Home

Kilka miesięcy temu pisałem o komponencie do rysowania wykresów firmy Xceed. Teraz postanowiłem przyjrzeć się dwóm innym komponentom: Komponent pierwszy jest do pobrania za darmo ze strony Microsoftu. Za drugi trzeba już płacić ale producent udostępnia wersję demonstracyjną.

Najpierw zainstalowałem komponent firmy Dundas. Od razu spodobał mi się program pokazujący przykłady różnych wykresów wraz z kodem. Dobre wrażenie sprawił również kreator zintegrowany z VS do konfigurowania kontrolki. Ogólnie pierwsze wrażenie bardzo pozytywne. Na dalszy ogień poszło rozwiązanie Microsoftu. W porównaniu do poprzednika od razu rzucił mi się w oczy brak kreatora i programu demonstracyjnego (można go pobrać oddzielnie tutaj).

Następnie zaczynam przyglądać się interfejsowi programistycznemu. Patrzę, patrzę i mam wrażenie deja vu. Pomimo pewnych różnic oba produkty mają bardzo, bardzo podobne API. Chwila zastanowienia i wpisuję w Google ''Microsoft Chart Control vs. Dundas Chart Control''. Pierwszy link i wszystko staje się jasne. Począwszy od roku 2007 Microsoft posiada prawa do własności intelektualnej firmy Dundas, a przejawem tego jest komponent Microsoft Chart Controls for Microsoft .NET Framework 3.5 oparty o kod Dundas Chart for .NET.

Podsumowując można za darmo pracować z bardzo fajną kontrolką pamiętając jednak o tym, że produkt Microsoftu posiada do pewnego stopnia ograniczoną względem oryginału funkcjonalności. Po drugie firma Dundas udziela wsparcie tylko na produkty zakupione bezpośrednio od nich. Nie jestem również pewny czy nowe usprawnienia, które wprowadzają programiści z Dundas są również dostępne w wersji Microsoftu (pewnie nie).

02/11/2009

Problem z SqlDependency. Czyżby?

Home

Post ten dotyczy mechanizmu query notification, który pozwala na otrzymywanie powiadomień o zmianach w bazie danych dotyczących wybranych wierszy. Funkcjonalność ta jest dostępna na poziomie programistycznym między innymi przez łatwą w użyciu klasę SqlDependency (Jest to opakowanie na klasę SqlNotificationRequest). W Internecie można znaleźć bardzo dużo przykładów użycia tej klasy nie będę, więc powielał tego co zostało już napisane. Chciałbym natomiast zwrócić uwagę, że chociaż warunkiem koniecznym użycia powiadomień jest użycie SQL Server'a w wersji 2005 lub późniejszej to nie jest to warunek wystarczający.

Wszystko zaczęło się od tego, że postanowiłem przyjrzeć się dokładnie temu mechanizmowi. Do testów wybrałem chyba dobrze znana bazę Northwind. Bardzo szybko udało mi się stworzyć testową aplikację ale po jej uruchomieniu okazało się, że powiadomienia nie są generowane albo aplikacja ich nie otrzymuje. Kod sprawdziłem kilka razy, dla pewności przejrzałem kilka opisów w sieci i nic.

W końcu postanowiłem wykorzystać kody pokazane w jednym z tutoriali, wraz z użytą w tam bazą danych. Po chwili okazało się, że działa. Zmodyfikowałem, więc swoją aplikację aby używała właśnie tej bazy danych. Chwila niepewności, uruchamiam i również działa.

Dochodzę do wniosku, że nie ma mocnych, problem musi tkwić gdzieś w bazie danych. Porównuję konfigurację obu baz danych i znajduję winnego - tryb kompatybilności. Okazało się, że po zainstalowaniu baza Northwind ma ustawiany tryb kompatybilności na SQL Server 2000, zamiast SQL Server 2005. Mała, głupia sprawa, a można stracić trochę czasu.

26/10/2009

CodeBehind i CodeFile

Home

Jakiś czas temu pisząc prostą aplikacje WWW utworzyłem z rozpędu projekt typu Web Application zamiast Web Site. Zanim się zorientowałem popełniłem już trochę kodu stwierdziłem więc, że nie będę pisał go od początku. Usunąłem projekt z solution, wykasowałem plik z rozszerzeniem csproj i skorzystałem z polecenia Add -> Existing Web Site.... Wszystko wydawało się w porządku do momentu kiedy spróbowałem skompilować aplikację. W efekcie otrzymałem komunikat jak poniżej:

Could not load type 'PageName'.

Przy drugiej próbie kompilacji otrzymałem taki sam błąd kompilacji. Patrzę i patrzę w kod strony i nic. Przecież jeszcze 5 minut temu kompilowało się, czary? Oczywiście, że nie. Po chwili przypominam sobie o jednej drobnej różnicy. W przypadku projektów typu Web Application w dyrektywie @Page używa się atrybutu CodeBehind, a w przypadku Web Site'ów atrybutu CodeFile. Niby szczegół ale jeśli się o nim zapomni może popsuć trochę krwi.

19/10/2009

Trochę o zwalnianiu zasobów

Home

Każdy dobry programista wie, że po skończeniu pracy z obiektem klasy implementującej interfejs IDisposable należy wywołać metodę Dispose (jawnie bądź nie jawnie). Dlatego kiedy ostatnio zobaczyłem kod, w którym programista beztrosko raz po raz tworzy ikonę, a następnie radośnie o niej zapomina powodując wzrost liczby obiektów GDI przez usta przeszły mi dość niecenzuralne słowa. Oczywiście od razu poprawiłem kod w mniej więcej taki sposób:
using(Icon icon = GetIcon())
{
   ...
}
Nic prostszego można powiedzieć. Jednak przy następnym uruchomieniu aplikacji ku mojemu zdziwieniu liczba obiektów GDI znowu zaczęła rosnąć. Zaglądam, więc do metody GetIcon. A tam widzę coś takiego:
return Icon.FromHandle(handle);
Nie kojarząc za bardzo metody FromHandle zaglądam do dokumentacji, a tam jest napisane coś takiego:

When using this method you must dispose of the resulting icon using the DestroyIcon method in the Win32 API to ensure the resources are released.

Kolejny mój krok to oczywiście sprawdzenie czy wywołanie DestroyIcon działa. Metodę tą należy zadeklarować w następujący sposób:
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet=CharSet.Auto)]
extern static bool DestroyIcon(IntPtr handle);
Jej użycie oczywiście rozwiązało problem. Co dociekliwsi mogą jeszcze zapytać czemu wywołanie Dispose nie wystarcza. Sprawa jest dość ciekawa. Okazuje się, że klasa Icon używa wewnętrznie DestroyIcon do zwalniania zasobów ale tylko i wyłącznie wtedy kiedy jest właścicielem tych zasobów to jest kiedy sama je zaalokuje. W momencie tworzenia ikony przy pomocy uchwytu dostarczonego z zewnątrz trzeba samemu zadbać o jego zwolnienie.

Reasumując w opisanym przypadku dwóch programistów zrobiło dwa poważne błędy. Pierwszy zapomniał o zwolnieniu zasobów, a drugi o dokładnym przeczytaniu dokumentacji. Metoda GetIcon powinna zostać napisana tak aby korzystający z niej programista nie musiał posiadać wiedzy "tajemnej" aby dobrze jej użyć.

11/10/2009

Kontrolki ASP.NET i zdarzenia

Home

Dzisiaj napiszę o rzeczy bardzo prostej ale, o której jednak zdarzyło mi się zapomnieć przez co zmarnowałem trochę czasu. Sytuacja miała miejsce kiedy pracowałem nad kontrolkę, która na swoim interfejsie publicznym między innymi udostępniała zdarzenia SelectionChanged. W kodzie wyglądało to jakoś tak:
...
public event EventHandler SelectionChanged;
...
Po jej napisaniu zabrałem się do testowania i jedną z rzeczy jaką chciałem sprawdzić było to czy zdarzenie jest generowane w odpowiednim momencie. Umieściłem więc kontrolkę na stronie w taki sposób:
...
<cc1:MyControl id="Control1" runat="server" SelectionChanged="Control1_SelectionChanged" />
...
Uruchamiam stronę i coś nie działa. Po krótkiej chwili dochodzę do wniosku, że coś musi być nie tak z zdarzeniem. Stawiam, więc w kodzie pułapkę i odświeżam stronę. Chwila debugu i konsternacja. Kod działa prawidłowo ale w momencie kiedy następuje próba wygenerowania zdarzenia okazuje się, że SelectionChanged równa się null.

Zaczynam sprawdzać czy nigdzie nie zrobiłem literówki itd. Uruchamiam kod ponownie i ciągle to samo. W końcu przypominam sobie, że aby deklaratywnie podczepić się pod zdarzenie kontrolki trzeba użyć przedrostka On. Kod powinien więc wyglądać jak poniżej:
...
<cc1:MyControl id="Control1" runat="server" OnSelectionChanged="Control1_SelectionChanged" />
...