12. Przechwytywanie i obsługa błędów w aplikacjach ASP.NET

12. Przechwytywanie i obsługa błędów w aplikacjach ASP.NET

Autor: Piotr Gaszewski

Opublikowano: 3/17/2006, 12:00 AM

Liczba odsłon: 44079

Nawet najlepiej napisana i najbezpieczniejsza aplikacja internetowa może odmówić prawidłowego działania w określonych warunkach. Aplikacja może „wywrócić się” pod wpływem nieumyślnego bądź też celowego działania użytkownika, niepoprawnie skonfigurowanego serwera lub też po prostu z powodu nie przewidzenia przez programistę zachowania aplikacji w określinych sytuacjach. Ważną sprawą jest obsługa przez aplikację opisanych wyżej sytuacji. Języki programowania działające na platformie .NET mają możliwość obsługiwania tak zwanych wyjątków – czyli najprościej mówiąc nie przewidywanych przez twórców programu, „wyjątkowych” sytuacji.

Wyobraźmy sobię sytuację, w której przy załadowaniu strony internetowej nasza aplikacja próbuje wyświetlić, odczytane uprzednio z pliku tekstowego informacje. Otwarcie pliku odbywać się będziew metodzie Page_Load.  

protected void Page_Load(object sender, EventArgs e)
{
      System.IO.FileStream fs = System.IO.File.Open(@"c:\plik", System.IO.FileMode.Open);

}

Podana w aplikacji ścieżka dostępu do pliku może być jednak nieprawidłowa, co może być spowodowane usunięciem pliku, brakiem uprawnień do jego odczytu, bądź też zwykłą pomyłką programistów lub osób wdrażających aplikację na serwerze. W opisanej wyżej sytuacji zamiast zawartości naszej formatki, w oknie przeglądarki internetowej ujrzymy następującą informację:

Nie chcemy oczywiście, aby tego typu informacje ukazywały się użytkownikom naszej aplikacji. Mogą one posłużyć rozmaitym intruzom lub włamywaczom do zdobycia informacji na temat środowiska zainstalowanego na serwerze, natomiast „zwyczajnych użytkowników sieci” będą po prostu niepokoić i irytować.

@STRONA@

Wyjątki możemy obsługiwać w prosty sposób używając do tego celu programowej konstrukcji: try – catch – finally. Jej działanie zaprezentujmy na przykładzie naszej formatki. Zmodyfikujmy zawartość metody Page_Load w następujący sposób:

protected void Page_Load(object sender, EventArgs e)
{
      try
      {
            System.IO.FileStream fs = System.IO.File.Open(@"c:\plik", System.IO.FileMode.Open);
     
}
      catch
      {
            Response.Write("Wystąpił błąd. Nie można odczytać pliku źródłowego");
      }

Tym razem po otwarciu strony w oknie przeglądarki ukaże się następujący widok:

Przeanalizujmy jak do tego doszło. Otóż każdy kod, mogący powodować błędy w działaniu aplikacji (w naszym przypadku będzie to próba otwarcia nieistniejącego w pliku) powinien znajdować się w klazuli „Try”. W momencie wystąpienia wyjątku, działanie kodu zostaje przerwane i aplikacja przechodzi do wykonywania instrukcji zawartej w klauzuli catch. W naszym przypadku program próbuje otworzyć nieistniejący plik. W momencie, kiedy wykonanie tej systuacji okazuje się niemożliwe, rozpoczyna się wykonywanie kodu obsługującego wyjątek. W przypadku naszej aplikacji będzie to wypisanie na standartowe wyjście odpowiedniej informacji. Używając tej klauzuli możemy również przechwytywać specyficzne rodzaje wyjątkowych sytuacji. Poniższy kod prezentuje przechwycenie wyjątku związanego z operacjami wejścia-wyjścia i wyświetlenia szczegółowej informacji na ten temat:

protected void Page_Load(object sender, EventArgs e)
{
      try
      {
            System.IO.FileStream fs = System.IO.File.Open(@"c:\plik", System.IO.FileMode.Open);
      }
      catch (System.IO.FileNotFoundException ex)
      {
            Response.Write("Wystąpił błąd: " + ex.Message);
      }
}

W powyższym kodzie nie występuje ostatnia część kodu umożliwiającego obsługę błędów, tzn. Dyrektywa: „Finally”. Umieszczamy ją zazwyczaj na koniec podobnych do powyższej instrukcji i zamieszczamy tam kod, który będzie wykonywany bez względu na prawidłowy lub niepoprawny przebieg operacji.

try
{
      ...
}

catch

{
      ...
}

finally

{
      objConnection.Close();

}

W powyższym przykładzie bez względu na wystąpienie wyjątku połączenie o nazwie objConnection zostanie zakończone.

@STRONA@

Języki działające na platformie .NET, takie jak Visual Basic czy C# dają programistom możliwość wyłapywania specyficznych rodzajów wyjątków. Kilka przykładowych błedów, które może „pochwalić się” posiadaniem zdefiniowanych przez twórców tych języków wyjątków to błąd przepełnienia bufora, upłynięcia określonego czasu oczekiwania, czy błąd nieautoryzowanego dostępu. Twórców aplikacji internetowych szczególnie interesują wyjątki, związane w systuacjami mogącymi wystąpić w trakcie działania witryn, pisanych w technologii ASP.NET.

Przechwycenia określonego wyjątku i wyświetlenie informacji związanej z tym wyjątkiem, dokonuje się w następujący sposób.

try
{
}

catch
(Exception ex)
{
      this.response.write(„Wystąpił błąd: „ + ex.Message);
}

Zastosowanie takiego kodu na stronie, powodującej wystąpienie błędu, może zaowocować przedstawionym poniżej rezultatem.

Możemy zapewnić również naszej aplikacji globalną obsługę błędów. W tym celu dodajemy do naszego projektu plik Web.config (Website -> Add New Item -> Web Confguration File), a następnie dodajemy do niego następujące linie (uwaga – muszą być one umieszczone między znacznikami <system.web></system.web>. Domyślnie przykładowe linie tego typu będą już się tam znajdować, tyle że będą zakomentowane.

<customErrors mode="On" defaultRedirect="GenericErrorPage.htm">
<
error statusCode="403" redirect="NoAccess.htm"/>
<
error statusCode="404" redirect="FileNotFound.htm"/>
</
customErrors> 

Poniższy plik konfiguracyjny zawiera obsługę standartowych błędów 403 i 404. W przypadku pojawienia się tych błedów nastąpi przekierowanie na zdefiniowane w pliku konfiguracyjnym strony. Domyślną stroną, na którą będzie następowało przekierowanie w przypadku wystąpienia innych sytuacji będzie „GenericErrorPage.htm”. W poniższej tabeli zamieszczam kilka najpopularniejszych kodów wraz z krótkimi opisami.

Kod

Opis

400

Format zapytania otrzymanego przez serwer jest niepoprawny.

401

Osoba nie ma odpowiednich uprawnień do oglądania zawartości strony

403

Serwer odmawia wykonania żądania

404

Szukana strona nie została odnaleziona na serwerze.

408

Przekroczony został czas oczekiwania na odpowiedź serwera

500

Wewnętrzny bład serwera. Kod ten reprezentuje wszystkie nieobsługiwane wyjątki w aplikacjach działających na serwerze

503

Usługa jest chwilowo niedostępna

505

Wersja protokołu HTTP,  używana przez klienta, jest nieobsługiwana przez serwer. 

Możemy również definiować obsługę błędów na poziomie poszczególnych plików *.aspx. W tym celu w rozpoczynającej stronę dyrektywie „<%@Page...%>” dodajemy właściwość o nazwie: errorPage.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" ErrorPage ="~/ErrDefault.aspx"  %>

W momencie wystąpienia nieobsługiwanego wyjątku, nastąpi przekierowanie na stronę ErrDefault.aspx