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
.