W tym rozdziale zostanie poruszone niezwykle ważne zagadnienie — testowanie stron ASP.NET. Wszyscy popełniamy błędy, niezależnie od tego jak doskonałymi programistami byśmy nie byli. Dlatego też konieczność testowania aplikacji jest oczywistym faktem. Im tworzony kod jest dłuższy, tym więcej w nim będzie błędów.
Jest całkiem prawdopodobne, że spotkałeś się już z wieloma błędami w programach komputerowych. Przypomnij sobie te wszystkie komunikaty generowane przez tradycyjne aplikacje bądź witryny WWW, opisujące błędy których zupełnie nie rozumiałeś. W większości przypadków błędy te oznaczały przerwanie pracy programu, lecz czasami zdarzało się także, iż powodowały one generowanie nieodpowiednich danych wynikowych. Niemniej jednak, w każdym z tych przypadków nie byłeś w stanie zrobić tego co zaplanowałeś. W idealnym przypadku powinniśmy napisać kod i zapomnieć o nim, jednak bardzo często jest to zupełnie nierealne.
ASP.NET udostępnia dwa wspaniałe narzędzia służące do testowania aplikacji — program uruchomieniowy CLR (ang.: Microsoft Common Language Runtime Debugger) oraz usługę śledzenia (ang.: Trace Service). Oba te narzędzia zostaną szczegółowo omówione w treści niniejszego rozdziału, podobnie jak instrukcje try i catch.
W tym rozdziale zostaną omówione następujące zagadnienia:
· Sposoby zastosowania instrukcji try oraz catch do testowania aplikacji.
· Testowanie aplikacji przy wykorzystaniu metody Response.Write.
· Sposoby tworzenia i zgłaszania własnych błędów.
· Czym jest narzędzie śledzenia oraz jak można z niego korzystać.
· W jaki sposób można wykorzystać program uruchomieniowy CLR do testowania aplikacji podczas jej działania.
Prawdopodobnie zdarzyło Ci się już popełnić kilka błędów podczas tworzenia stron ASP.NET. Mogły to być proste błędy polegające na pominięciu atrybutu runat="server", lub całkiem złożone, których odnalezienie wymagało długich dni żmudnej pracy. Błędy są bardzo frustrujące, a ciągłe oglądanie stron zawierających komunikaty o nich (takich jak ta przedstawiona na rysunku 20.1) może sprawić, że będziesz chciał wyrywać sobie włosy z głowy.
Rysunek 20.1. Typowa strona z informacjami o błędach, generowana przez ASP.NET.
Wraz ze wzrostem stopnia złożoności tworzonych aplikacji, coraz trudniej jest zapobiegać powstawaniu nowych błędów oraz odnajdywać i poprawiać błędy, które już zostały zrobione. Przyjrzymy się typowemu przykładowi przedstawionemu na listingu 20.1.
Listing 20.1. Odnajdywanie błędów.
1 <%@ Page Language="VB %>
2 <%@ Import Namespace="System.Data" %>
3 <%@ Import Namespace="System.Data.OleDB" %>
4
5 <script runat="server">
6 sub Page_Load(obj as Object, e as EventArgs)
7 'tworzymy połączenie
8 dim objConn as new OleDbConnection _
9 ("Provider=Microsoft.Jet.OLEDB.4.0;" & _
10 "Data Source=C:\ASPNET\data\banking.mdb")
11
12 'otwieramy połączenie
13 dim objCmd as new OleDbDataAdapter _
14 ("select * from tblUsers", objConn)
15
16 'pobieramy dane
17 dim ds as DataSet = new DataSet()
18 objComm.Fill(ds, "tblUsers")
19 end sub
20 </script>
21
22 <html><body>
23 <form runat="server">
24
25 </form>
26 </body></html>
Spróbuj wyświetlić tę stronę w przeglądarce (nie zapomnij wcześniej włączyć testowania w pliku konfiguracyjnym web.config). W przeglądarce pojawi się strona przypominające tą z rysunku 20.2.
Rysunek 20.2. Ojej, coś złego stało się z kodem naszej strony
Jest oczywiste, że kod przedstawiony na listingu 20.1 nie jest w porządku; a jeśli jeszcze nie zauważyłeś gdzie znajduje się błąd, to informacje wyświetlone na stronie z rysunku 20.2 pomogą Ci go odnaleźć. Warto zwrócić uwagę, iż na stronie z rysunku 20.2 został wyróżniony wiersz kodu źródłowego, w którym wystąpił błąd, a dodatkowo zostały na niej wyświetlone informacje o numerze tego wiersza oraz nazwie pliku. Wygląda na to, że w wierszu 18 popełniliśmy prosty błąd typograficzny. Zamiast nazwy objCmd została użyta nazwa objComm. Dzięki szczegółowym informacjom wyświetlanym na stronie, błąd tego typu można bardzo łatwo poprawić. Po wprowadzeniu stosownych zmian, nasz kod będzie działać bez zarzutu.
Przyjrzyjmy się dokładniej stronie z rysunku 20.2. Łatwo zauważyć, iż zawiera ona całkiem sporo dodatkowych informacji o przyczynie błędu. Na przykład, u dołu tej strony znajdują się dwa połączenia — Show Detailed Compiler Output (pokaż szczegółowe wyniki wygenerowane przez kompilator) oraz Show Complete Compilation Source (pokaż kompletny kod źródłowy użyty podczas kompilacji strony). Kliknięcie tych połączeń spowoduje wyświetlenie na stronie nowych informacji, przedstawionych na rysunku 20.3.
Rysunek 20.3. Bardziej szczegółowe informacje o błędzie
NotatkaJeśli nie został włączony tryb testowania, to dwa opisywane połączenia do dodatkowych informacji na temat błędu, mogą być niedostępne. Więcej informacji na ten temat znajdziesz w rozdziale 18., pt.: „Konfiguracja i wdrażanie aplikacji ASP.NET”.
UWAGA! W rozdziale 18 nie ma ani słowa o testowaniu ani o konfigurowaniu czegokolwiek związanego z testowaniem. Proponuję zatem, zmienić drugie zdanie na: Więcej informacji na temat konfigurowania stron ASP.NET znajdziesz w rozdziale 18., pt. „Konfiguracja i wdrażanie aplikacji ASP.NET”.
Fragment strony wyświetlany po kliknięciu pierwszego z tych połączeń — Show Detailed Compiler Output — zawiera informacje o tym, co mechanizmy ASP.NET próbowały wykonać i dlaczego im się to nie udało. Jego pierwszy wiersz zawiera polecenie, które zostało wydane w celu skompilowania kodu źródłowego strony ASP.NET. (Jak widać został do tego celu użyty kompilator języka Visual Basic.NET.) Po sprawdzeniu parametrów wywołania kompilatora oraz wykorzystanych w tym poleceniu obiektów biznesowych, wszystkie pozostałe elementy polecenia powinne być znajome.
Poniżej polecenia, zostały wyświetlone wyniki wygenerowane przez kompilator, które mogą nam pomóc przy określaniu przyczyny błędu. Ten komunikat jest widoczny także na rysunku 20.2. Fragment strony wyświetlany po kliknięciu drugiego połączenia — Show Complete Compilation Source — prezentuje pełny kod źródłowy pliku, który miał być skompilowany, w tym także wszelkie polecenia kompilatora oraz funkcje maszyny wirtualnej CLR.
Ogólnie rzecz biorąc, udostępnianie tych informacji użytkownikom końcowym nie jest zalecane. Przed wszystkim, większość użytkowników w ogóle nie chce oglądać jakichkolwiek komunikatów o błędach. A co gorsze, sprytny użytkownik może wykorzystać ten kod przeciwko nam. A zatem, jest niezwykle ważne, aby przetestować strony przy użyciu wszelkich dostępnych środków i narzędzi, i zrobić wszystko co możliwe, aby takie komunikaty o błędach się nie pojawiały.
Na szczęście ASP.NET udostępnia kilka mechanizmów, które pomagają przy testowaniu aplikacji i obsłudze błędów. Pierwszy z nich został przedstawiony już wcześniej — są nim instrukcje try oraz catch umieszczane w różnych miejscach programów (na przykład, w listingu 19.1, przedstawionym w poprzednim rozdziale). Instrukcje te pozwalają na przechwytywanie potencjalnych błędów, które mogą wystąpić w aplikacji. W podobny sposób może nam pomóc narzędzie śledzące, które oprócz tego udostępnia dodatkowe informacje. I w końcu ostatnim narzędziem które można wykorzystać podczas testowania aplikacji, jest program uruchomieniowy CLR. Jest to potężne narzędzie służące do odnajdywania i poprawiania błędów, które się już pojawiły.
Zazwyczaj, gdy jakiś fragment kodu spowoduje błąd, to wykonywanie aplikacji zostaje przerwane, a w przeglądarce jest wyświetlany stosowny komunikat o błędzie (przykładowa postać takiego komunikatu została przedstawiona na rysunku 20.1). Jeśli istnieje jakakolwiek możliwość uniknięcia wyświetlenia tego komunikatu, to należy ją wykorzystać (w końcu, w idealnym przypadku, błędy nigdy nie powinne byś wyświetlane).
Użycie instrukcji try informuje ASP.NET że pewien blok kodu należy wykonać „próbnie”. W takim przypadku, jeśli jakikolwiek fragment kodu zapisany wewnątrz tej instrukcji spowoduje zgłoszenie błędu, to nie doprowadzi on do przerwania wykonywania aplikacji i wyświetlenia stosownego komunikatu, lecz będziemy mieli szansę rozwiązania zaistniałego problemu. Na przykład, gdyby wiersz 18. listingu 20.1 został zapisany wewnątrz instrukcji try, to istniałaby potencjalna szansa uniknięcia zatrzymania aplikacji przez zgłaszany błąd i jej dalszego wykonywania.
Instrukcja try służy do ochrony fragmentów kodu, które mogą spowodować powstanie błędów. W przypadku tworzenia tradycyjnych aplikacji stosowanie tych instrukcji jest koniecznością, gdyż wykonanie niektórych operacji na pewno spowoduje zgłoszenie błędu. Być może o tym nie wiesz, ale kliknięcie przycisku Anuluj w oknie dialogowym zazwyczaj powoduje zgłoszenie błędu, który aplikacja w jakiś sposób musi obsłużyć. Instrukcja try oraz inne instrukcje używane wraz z nią, są wspólnie określane mianem strukturalnej obsługi wyjątków.
Analizując przykłady podane w niniejszej książce można się już było przekonać, że składnia instrukcji try jest całkiem prosta. Składa się ona z instrukcji try, po którym jest umieszczany chroniony blok kodu, po którym są z kolei umieszczane instrukcje catch oraz finally. Oto przykład zapisu tej instrukcji:
1 'tworzymy obiekt OleDbCommand
2 try
3 objCmd.Connection.Open
4 '....
5 catch
6 obsługa błędu
7 end try
W tym przypadku chroniony jest kod zapisany pomiędzy wierszami 2. i 5., gdyż to właśnie on może spowodować zgłoszenie błędu. Jeśli wewnątrz bloku try nie został zgłoszony żaden błąd, to wykonywanie programu zostaje przeniesione do wiersza 7., a pozostały kod jest realizowany w standardowy sposób. Jeśli jednak błąd zostanie zgłoszony, to wykonywanie programu zostanie przeniesione do instrukcji catch zapisanej w wierszu 5. Wewnątrz tej instrukcji umieszczany jest kod służący do obsługi błędu.
Nowe wyrażenie
Przyjrzyjmy się bliżej technicznym szczegółom całego procesu. Gdy w aplikacji VB.NET pojawia się błąd to mówimy że został zgłoszony wyjątek. Oznacza to, że stało się coś co nie powinno się stać i VB.NET „rzuca w powietrze” błąd, aby ktoś inny go złapał i obsłużył. Jeśli wyjątek nie zostanie w żaden sposób obsłużony, to błąd spowoduje przerwanie realizacji aplikacji a informacje o błędzie zobaczy użytkownik końcowy.
Zgłaszanie wyjątków pozwala na przechwytywanie błędów zanim doprowadzą one do przerwania wykonywania aplikacji i wyświetlenia stosownego komunikatu. Jeśli błąd w porę zostanie przechwycony, to istnieje możliwość zapobieżenia awarii i rozwiązania zaistniałego problemu.
Spróbujmy zatem użyć instrukcji try. Gdy pojawi się błąd instrukcja ta zaalarmuje towarzyszącą jej instrukcję catch, która przechwyci wyjątek i obsłuży go. Listing 20.2 przedstawia przykład zastosowania tych instrukcji.
Listing 20.2. Przykład testowania strony ASP.NET.
UWAGA!! W oryginale była różnica pomiędzy kodem przykładu wydrukowanym w tekście książki i kodem zamieszczonym w przykładach. W tłumaczeniu użyłem wersji z przykładów, gdyż odpowiada ona wynikom pokazanym na rysunku 20.4. Zmieniły się także numery wierszy zastępowanych przez kod z listingu 20.3 (jest to tym mowa po listingu 20.2).
1 <%@ Page Language="VB" Debug="true" %>
3 <%@ Import Namespace="System.Data.OleDb" %>
6 dim Conn as new OleDbConnection("Provider=" & _
7 "Microsoft.Jet.OLEDB.4.0;" & _
8 "Data Source=C:\ASPNET\data\banking.mdb")
9
10 sub GetData(obj as Object, e as EventArgs)
11 dim objCmd as OleDbCommand = new OleDbCommand _
12 ("select * from tblUsers where UserID = @ID", Conn)
13 dim objReader as OleDbDataReader
14
15 dim objParam as OleDbParameter
16 objParam = objCmd.Parameters.Add("@ID", OleDbType.Integer)
17 objParam.Direction = ParameterDirection.Input
18 objParam.Value = tbID.Text
19
20 objCmd.Connection.Open()
21 objReader = objCmd.ExecuteReader
22
23 dgData.DataSource = objReader
24 dgData.DataBind()
25
26 objReader.Close
27 objCmd.Connection.Close()
28 end sub
29 </script>
30
31 <html><body>
32 <form runat="server">
33 <asp:Label id="lblMessage" runat="server"
34 maintainstate=false /><br>
35 Podaj identyfikator: <asp:TextBox id="tbID" runat="server"
36 AutoPostBack=True
37 OnTextChanged=GetData /><p>
38 <asp:DataGrid id="dgData" runat="server"
39 BorderColor="black"
40 GridLines="Vertical"
41 width="100%"
42 Font-Name="Arial"
43 Font-Size="8pt"
...
grzegorj