Najcz
ęś
ciej popełniane bł
ę
dy
w ASP.NET
W tym dodatku zostało opisanych wiele błędów najczęściej popełnianych przez programistów
ASP.NET i to niezależnie od tego czy są oni zupełnie początkujący czy też mają duże
doświadczenie w tworzeniu aplikacji w tradycyjnej technologii ASP. Istnieje wiele przykładów
prostych błędów, które mogą sprawić, że programiści będą łamać sobie głowy próbując określić co
się dzieje. W rzeczywistości wiele spośród tych błędów można bardzo łatwo poprawić. Dodatek
ten został napisany w formie krótkiego poradnika prezentującego takie błędy. Dzięki niemu
programiści ASP.NET będą w stanie błyskawicznie znaleźć przyczynę błędu, poprawić go oraz
dowiedzieć się jak w przyszłości unikać błędów tego typu.
Niniejszy dodatek został podzielony na dwie części. W pierwszej z nich zostały opisane błędy
typowe dla technologii ASP.NET, które bardzo często pozostają niezauważone. W drugiej części
opisane zostały zmiany, na które należy zwrócić szczególną uwagę przy przerabianiu klasycznych
stron ASP na strony ASP.NET. Między innymi chodzi tu także o ogromne różnice syntaktyczne
pomiędzy językami VBScript a VB.NET.
Zagadki ASP.NET
ASP.NET ma wiele szczególnych cech, które mogą się stać przyczyną prawdziwych tragedii
programistycznych. Każda z sekcji podanych w tej części rozdziału podaje typowe komunikaty o
błędach wyświetlane w razie napotkanie konkretnego problemu, szczegółowy opis tego problemu
oraz sposób jego rozwiązania. (Należy zwrócić uwagę iż fragmenty komunikatów o błędach
wyświetlone kursywą, mogą zostać zastąpione bardziej szczegółowymi nazwami.)
Problemy z formularzami internetowymi
Problem
:
Unexpected end of file looking for </asp:Control> tag.
(Nieoczekiwany koniec pliku podczas poszukiwania zamykającego znacznika </asp:Control>)
Opis
: Zapomniano o zamykającym znaczniku elementu sterującego ASP.NET.
Rozwiązanie
: Wszystkie elementy sterujące muszą posiadać odpowiednie znaczniki zamykające.
Należy dodać znacznik zamykający zapisany w jeden z następujących sposobów:
<asp:Label id="lblKomunikat" runat=”server” />
<asp:Label id="lblKomunikat" runat=”server” />
Problem
:
Literal content ("html") is not allowed within a 'control'.
(Zawartość tekstowa („html”) nie może być umieszczona wewnątrz elementu sterującego
‘elemSter’)
Opis
: Próbowano utworzyć element sterujący bez koniecznego znacznika zamykającego.
Rozwiązanie
: Problemy tego typu występują zazwyczaj w przypadku stosowania elementów
sterujących
DataGrid
oraz
DataList
i są spowodowane pominięcie zamykającego znacznika
elementu sterującego. Bez tego znacznika ASP.NET przyjmuje że cały dalszy kod HTML strony
jest elementem tego elementu sterującego i dlatego zgłasza błąd. Aby rozwiązać problemy tego
typu wystarczy dopisać odpowiedni znacznik zamykający.
Problem
: Element sterujący nie jest wyświetlany lub nie działa zgodnie z oczekiwaniami.
Opis
: ASP.NET nie obsługuje poprawnie elementu sterującego; dane przesyłane z formularza nie
są rozpoznawane, właściwości określające wygląd elementu nie są wyświetlane, i tak dalej.
Rozwiązanie
: Najbardziej prawdopodobną przyczyną występowania tych problemów jest
pominięcie atrybutu
runat="server"
elementu sterującego. Aby rozwiązać problem, należy
dodać ten atrybut do elementu w którym występują problemu.
Problem
: Dane nie są poprawne wyświetlane w elemencie sterującym.
Opis
: ASP.NET w ogóle nie wyświetla danych w elemencie sterującym, bądź też nie uaktualnia
ich poprawnie.
Rozwiązanie
: Zapomniano o wywołaniu metody
DataBind
.
Problem
:
An exception has been thrown by the class contstructor for
System.Drawing.Internal.SystemColorTracker.
(Konstruktor klasy
System.Drawing.Internal.SystemColorTracker
zgłosił wyjątek.)
Opis
: ASP.NET nie jest w stanie poprawnie wyświetlić danego elementu sterującego (zazwyczaj
dotyczy to elementów
DataGrid
).
Rozwiązanie
: Uruchom ponownie aplikację. Można to zrobić na kilka sposobów:
•
z poziomu wiersza poleceń uruchomić program
iisreset
;
•
zmodyfikować i zapisać na dysku jeden z plików
global.asax
lub
web.config
;
•
ponownie skompilować któryś z obiektów biznesowych zapisanych w folderze
/bin
.
Problem
: Procedury obsług zdarzeń nie generują oczekiwanych wyników.
Opis
: Korzystając z formularzy internetowych i elementów sterujących wykonywanych po stronie
serwera starasz się wygenerować odpowiednie dane wyjściowe, ale coś nie działa zgodnie z
oczekiwaniami. Na przykład, próbujesz zmodyfikować zawartość pola tekstowego lub etykiety,
lecz wartość ta się nie zmienia lub zmienia się nie tak byś sobie tego życzył.
Rozwiązanie
: Trzeba pamiętać, że zdarzenie
Page_Load
jest zawsze wykonywane przed
wszystkimi innymi procedurami obsługi zdarzeń, które z kolei nie są wykonywane w żadnej
określonej kolejności. Procedura
Page_Load
może modyfikować lub przywracać oryginalną
wartość elementu sterującego zanim procedura obsługi zdarzenia będzie miała szansę użyć tej
wartości. Taką sytuację demonstruje poniższy fragment kodu:
sub Page_Load(obj as Object, e as EventArgs)
tbMessage.Text = "Witaj
Ś
wiecie!"
end sub
sub HandleSubmit(obj as Object, e as EventArgs)
Response.Write(tbMessage.Text)
end sub
...
<asp:TextBox id="tbMessage" runat="server"
OnTextChanged="HandleSubmit"
AutoPostBack=true />
...
W przypadku zmiany zawartości pola tekstowego, formularz jest przesyłany na serwer. Jednak w
pierwszej kolejności jest wykonywana metoda
Page_Load
która za każdym razem zapisuje w
polu tekstowym łańcuch znaków „
Witaj
Ś
wiecie!
”. Dopiero potem procedura
HandleSubmit
próbuje wyświetlić zawartość pola tekstowego, lecz zamiast podanego tekstu za każdym razem
wyświetlany jest łańcuch znaków „
Witaj
Ś
wiecie!
”.
Jednym z możliwych rozwiązań jest sprawdzenie w procedurze
Page_Load
wartości właściwości
Page.IsPostBack
, na podstawie której można określić czy formularz został wypełniony. W
takim przypadku a wartości jego pól nie powinne być zmieniane:
sub Page_Load(obj as Object, e as EventArgs)
if not Page.IsPostBack then
tb.Message.Text = "Witaj
Ś
wiecie!"
end if
end sub
Innym sposobem jest zmiana struktury używanych procedur.
Inne problemy
Problem:
MissingMethodException: Member not found.
(MissingMethodException: Nie
odnaleziono metody lub właściwości)
Opis: Została podjęta próba odwołania się do metody lub właściwości obiektu (zazwyczaj
zwróconego jako wynik działania jakiejś metody).
Rozwiązanie: Choć istnieje wiele potencjalnych przyczyn tych błędów, to jednak ten najczęściej
spotykany wiąże się z rzutowaniem typów. Na przykład przeanalizujmy poniższą procedurę
obsługi zdarzeń:
sub MyHandler(obj as Object, e as EventArgs)
Response.Write(obj.Text)
end sub
Zakładają że powyższa procedura jest wywoływana w celu obsługi zdarzeń generowanych przez
etykietę, to powinniśmy mieć możliwość dostępu do jej właściwości
Text
. Jednak nigdy nie
należy polegać na tym, co dana zmienna powinna reprezentować. Powinniśmy natomiast
odpowiednio rzutować typ obiektu:
Response.Write(CType(obj, Label).Text)
W ASP.NET zmienne typu
Object
często wykorzystują mechanizm wczesnego łącznia, co
oznacza, że mogą być przetwarzane już w czasie kompilacji strony (a nie w czasie obsługi
zgłoszonego żądania). Właśnie z tego powodu ASP.NET uważa odwołanie do właściwości
Text
za błąd — bo przecież klasa
Object
nie definiuje takiej właściwości. Niemniej jednak, w czasie
obsługi żądania zostanie przesłane odpowiednie odwołanie; wtedy jednak jest już za późno.
Należy pamiętać, aby zawsze odpowiednio rzutować typy zmiennych.
Problem:
The type obiekt in Assembly nazwa, Version=wersja,
Culture=kultura, PublicKeyToken=
ż
eton is not marked as serializable.
(Typ
obiekt w komponencie nazwa, o podanej kulturze i żetonie klucza publicznego nie został
oznaczony jako umożliwiający serializację.)
Opis: Została podjęta próba zachowania obiektu w sesji lub stanie aplikacji.
Rozwiązanie: Niektóre obiekty, takie jak na przykład obiekty
DataSet
nie mogą być
automatycznie zapisywane służących do przechowywania stanu. Aby rozwiązać ten problem
należy spróbować wywołać metodę ShouldSerializeObiekt obiektu który sprawia problemy.
Problem:
Type not defined: typ.
(Typ typ nie został zdefiniowany)
Opis: Została podjęta próba zadeklarowania kopii obiektu nieznanego typu.
Rozwiązanie: Należy się upewnić czy nazwa typu została zapisana poprawnie. Warto także
sprawdzić czy są importowane wszystkie konieczne przestrzenie nazw. Należy pamiętać, że w
klasach języka VB.NET (takich jak kod obsługi formularzy oraz obiekty biznesowe) przestrzenie
nazw nie są importowane domyślnie (jak to się dzieje w przypadku stron ASP.NET).
Zmiany w stosunku do tradycyjnej
technologii ASP
Przekształcając strony ASP pisane w języku VBScript do postaci stron ASP.NET pisanych w
języku VB.NET programiści często popełniać błędy syntaktyczne oraz problemy innych typów.
Błędy te oraz sposoby ich rozwiązywania zostały opisane w tej części niniejszego dodatku.
Problemy z j
ę
zykiem VBScript
Błąd:
Wend is no longer supported; use End While instead.
(Słowo kluczowe
Wend nie jest już stosowana, zamiast niej należy użyć instrukcji End While)
Opis: Próbowano zakończyć pętlę
while
przy użyciu słowa kluczowego
wend
.
Rozwiązanie: W języku VB.NET słowo kluczowe
wend
nie jest dostępne, zamiast niego należy
użyć instrukcji
End While
.
Błąd:
The syntax <lower bound> To <upper bound> is no longer supported for
specifying array bounds.
(Składnia <dolna granica> To <górna granica> nie jest już
stosowana do określania zakresu indeksów tablic)
Opis: Została podjęta próba określenia stałej wielkości tablicy.
Rozwiązanie: W języku VBScript dopuszczalne było użycie instrukcji
dim MyArray(0, 5)
w
celu utworzenia tablicy o stałej wielkości. W ASP.NET nie jest to możliwe.
Błąd:
The name 'mojaTablica' is not declared.
(Zmianna mojaTablica nie została
zadeklarowana, przy czym mojaTablica jest tablicą)
Rozwiązanie: Prawdopodobnie została podjęta próba zadeklarowania tablicy przy użyciu instrukcji
ReDim
. Zanim będzie można jej użyć trzeba zadeklarować tablicę przy użyciu instrukcji
Dim
.
Błąd:
A value of type 'type' cannot be conferted to object.
(Wartość typu ‘typ’
nie może zostać skonwertowana do obiektu)
Opis: Zazwyczaj oznacza to, że została podjęta próba przypisania właściwości do obiektu, bez
określania nazwy właściwości
Rozwiązanie: W języku VBScript obiekty dysponowały tak zwanymi domyślnymi
właściwościami. Innymi słowy, nie trzeba było podawać nazwy takiej właściwości aby określić jej
wartość. A zatem, posługując się hipotetycznym przykładem wykorzystującym element sterujący
Label
, w języku VBScript można by użyć następującego fragmentu kodu:
dim Lable as Label
Label = "Witaj
Ś
wiecie!"
Wykonanie powyższego fragmentu kodu spowodowałoby przypisani właściwości
Text
podanego
łańcucha znaków. W języku VB.NET domyślne właściwości nie są już dostępne, chyba że
używają parametrów. Oznacza to że należy jawnie podawać nazwy właściwości:
Label.Text = "Witaj
Ś
wiecie!"
Problem:
Let and Set are no longer supported on assignment statements.
(Przy
przypisaniach nie są już stosowane słowa kluczowe Let i Set)
Opis: Została podjęta próba przypisania czegoś do obiektu przy wykorzystaniu słowa kluczowego
Let lub Set.
Rozwiązanie: Słowa kluczowe
Let
i
Set
nie są stosowane w języku VB.NET; wystarczy je
usunąć z kodu i wszystko powinno być w porządku.
Problem:
The name 'N' is not declared.
(Nazwa ‘N’ nie została zadeklarowana) Nawet
pomimo faktu, że ją deklarowałeś.
Opis: Deklaracja zmiennej z jednej części strony nie jest dostępna w innej części tej samej strony.
Rozwiązanie: W języku VBScript zmienne deklarowane wewnątrz instrukcji blokowych (czyli
dowolnych instrukcji kończących się słowami kluczowymi
End
,
Next
bądź
Loop
) były widoczne
poza blokiem, w którym zostały zadeklarowane. Na przykład, wykonanie poniższego fragmentu
kodu spowoduj wyświetlenie w przeglądarce liczby 11:
dim I as integer
For I = 1 To 10
Dim N as Double
N = N + I
Next
Response.Write(N)
W języku VB.NET zmienna
N
będzie widoczna wyłącznie w bloku, w jakim została
zadeklarowana — poza nim nie będzie dostępna (co oznacza że będzie niedostępna poza pętlą
For
). Właśnie z tego powodu powyższy fragment kodu umieszczony na stronie ASP.NET nie
będzie poprawny. Aby rozwiązać powyższy problem wystarczy zadeklarować zmienną poza pętlą.
Problem:
Optional parameters must always specify a default value.
(Parametry
opcjonalne zawsze muszą określać wartość domyślną)
Opis: Zadeklarowałeś funkcję wykorzystującą słowo kluczowe
optional
, określające że dany
parametr jest opcjonalny.
Rozwiązanie: W języku VB.NET parametry opcjonalne muszą określać domyślną wartość. Na
przykład, poniższy fragment kodu zapisany w języku VBScript:
sub MySub(Optional mParametr as String)
należy zmienić na:
sub MySub(Optional mParametr as String = "Witam!")
Warto także widzieć, że funkcja IsMissing, służąc w języku VBScript do określania czy dany
została podana wartość określonego parametru opcjonalnego, w języku VB.NET nie jest dostępna.
Problem:
Argument lists in all call statements must now be enclosed in
parentheses.
(Teraz, listy argumentów we wszystkich wywołaniach muszą być zapisywane w
nawiasach)
Opis: Została podjęta próba wywołania funkcji lub procedury, której argumenty wywołania nie
zostały zapisane w nawiasach. Na przykład:
Response.Write "Witaj
Ś
wiecie!"
Rozwiązanie: W języku VB.NET argumenty podawane w wywołaniach wszystkich funkcji lub
procedur muszą być zapisywane w nawiasach, niezależnie od tego czy dana funkcja zwraca
wartość czy nie. Oznacza to, że zamiast powyższy fragment kodu należy zmienić w następujący
sposób:
Response.Write("Witaj
Ś
wiecie!")
Problem:
Type-declaration character & does not match declared data type
typ.
(Znak deklaracyjny & nie odpowiada deklarowanemu typowi danych typ)
Opis: Znak & został wykorzystany do konkatenacji łańcuchów znaków.
Rozwiązanie: W języku VBScript możliwe było łączenie łańcuchów przy wykorzystaniu operatora
&
bez umieszczania odstępów pomiędzy operatorem a nazwami zmiennych. Na przykład,
wykonanie poniższego fragmentu kodu napisanego w języku VBScript spowodowałoby
wyświetlenie w przeglądarce napis „
Witaj pi
ę
kny
Ś
wiecie!
”:
dim a as string = "Witaj "
dim b as string = "pi
ę
kny "
dim c as string = "
Ś
wiecie!"
Response.Write(a&b&c)
W ASP.NET powyższy fragment kodu spowoduje zgłoszenie błędu. Aby rozwiązać problem
należy zmienić ostatni wiersz powyższego przykładu w następujący sposób:
Response.Write(a & b & c)
Problemy z klasycznymi stronami ASP
Problem:
Syntax Error or Expected variable, constant, Enum, Type or
procedural declaration.
(Błąd syntaktyczny lub oczekiwana zmienna, stała, typ
wyliczeniowy, typ lub deklaracja proceduralna)
Opis: Deklaracja metody lub zmiennej globalnej nie jest prawidłowa. Została podjęta próba
zadeklarowania zmiennej lub metody wewnątrz bloku generowania kodu. Na przykład:
<%
dim I as Integer
sub Powitanie
...
end sub
%>
Rozwiązanie: W języku VB.NET wszystkie deklaracje metod i zmiennych globalnych muszą być
umieszczane w blokach deklarowania kodu (czyli pomiędzy znacznikami
<script>
). Co więcej,
wszystkie instrukcje, które nie są przypisaniami, muszą być umieszczane wewnątrz metod, takich
jak
Page_Load
.
Problem: Obiekt
Request
nie zwraca oczekiwanych danych.
Opis: Została podjęta próba użycia obiektu Request do zwrócenia danych z żądania HTTP; na
przykład
Request.Form
lub
Request.QueryString
.
Rozwiązanie: W klasycznej technologii ASP, obiekt Request zwracał łańcuch znaków zawierający
całą kolekcję zmiennych. Na przykład, zakładając, że klasyczna strona ASP została wywołana
przy użyciu adresu URL:
http://localhost/test/Test.asp?val=45&val=453
, to poniższe wywołanie:
Response.Write(Request.Querystring(val))
spowodowałoby wyświetlenie w przeglądarce jednego łańcucha znaków
45, 453
. W ASP.NET
obiekt Request zwraca tablicę łańcuchów znaków a nie jeden połączony łańcuch. Na przykład,
gdyby przy użyciu powyższego adresu URL została wywołana strona ASP.NET, to wywołanie
Response.Write(Request.Querystring(val)(0))
spowodowałoby wyświetlenie liczy
45
, natomiast wywołanie
Response.Write(Request.Querystring(val)(1))
spowodowałoby wyświetlenie liczby
453
. W powyższy sposób działa obiekt
Request
, oraz
właściwości
Request.Querystring
oraz
Request.Form
.