Filtry wyjątków w ASP .NET MVC

W ASP.NET MVC istnieją 4 rodzaje filtrów.

  • Filtry autoryzujące
  • Filtry wyjątku
  • Filtry akcji (przed akcją i po akcji)
  • Filtry rezultatu (przed i po wyniku akcji)

Poniżej omówię filtry wyjątku. Filtrów używa się jak atrybutów i dekoruje się nimi metody akcji. Są dwa sposoby używania filtrów wyjątku. Pierwszy to utworzenie własnego atrybutu obsługującego wyjątki. Drugi to skorzystanie z wbudowanego filtra.

Filtry wyjątku są uruchamiane jako wyłącznie wtedy gdy metoda zgłosi nieobsłużony wyjątek.

Ciekawostka. Wyjątek może pochodzić od innego rodzaju filtra, metody akcji i wyniku metody.

Pierwsza metoda tworzenie filtra wyjątku jest prosta i polega na implementacji interfejsu IExceptionFilter.

public class WyjatekZakresu : FilterAttribute, IExceptionFilter
{
  public void OnException(ExceptionContext filterContext)
  {

  }
}

Ponieważ chcemy używać klasy WyjatekZakresu jako filtr w MVC musimy implementować jeszcze interfejs IMvcFilter. Jednak w tym przypadku łatwiej będzie użyć klasy bazowej FilterAttribute, która zawiera w sobie interfejs IMvcFilter.

W tym przypadku będziemy obsługiwać wyjątek NullReferenceException.

public class WyjatekZakresu : FilterAttribute, IExceptionFilter
{
  public void OnException(ExceptionContext filterContext)
  {
     if (!filterContext.ExceptionHandled && filterContext.Exception is NullReferenceException)
     {
        var AktualnaStrona = filterContext.HttpContext.Request.QueryString["strona"];

       filterContext.Result = new ViewResult
       {
         ViewName = "BrakStrony",
         ViewData = new ViewDataDictionary<string>(AktualnaStrona )
       };

          filterContext.ExceptionHandled = true;
 
     }

  }
}

filterContext.ExceptionHandled mówi nam, czy wyjątek został już obsłużony. Dzięki temu możemy uniknąć sytuacji, że wyjątek jest łapany wiele razu.
filterContext.Exception  trzyma wyjątek, który został wywołany. W tym przypadku sprawdzamy złapany wyjątek jest jest typu NullReferenceException.

filterContext.HttpContext.Request.QueryString jest pomocniczą metodą aby przekazać parametr do widoku. Parametr ten jest pobrany z adresu strony. Nie jest to zalecana metoda ale czasem oszczędza trochę czasu.

filterContext.Result tworzy widok, który zostanie wywołany jeśli WyjątekZakresu się pojawi.

Innym sposobem może być przekierowanie użytkownika na inną stronę. Najprostszym sposobem było by w tym przypadku użycie metody:


filterContext.Result = new RedirectResult("~/Content/BrakStrony.html");

RedirectResult tworzy przekierowanie do strony BrakStrony.html

Aby zastosować filtr wyjątku należy udekorować metodę akcji w kontrolerze.

[WyjatekZakresu]
public ActionResult Nastepna(string strona)
{
  // Kod kontrolera rzucający wyjątek NullReferenceException
}
            

 Jedynym minusem takiego rozwiązania jest to, że może się zdarzyć sytuacja, że złapiemy nie prawidłowy wyjątek. To znaczy w widoku, który będziemy wyświetlać użytkownikowi podczas napotkania błędu będzie błąd i całe nasze wysiłki aby uniknąć pokazania użytkownikowi żółtego ekranu śmierci pójdą na marne. Użytkownik zobaczy żółty ekran śmierci i do tego będzie wprowadzony w błąd co tak naprawdę się stało.

Druga metoda jest jeszcze prostsza. Pozwala używać wbudowanego filtra wyjątków. W ASP .NET jest to HandleErrorAttribute. (kod źródłowy dla geeków) Poniżej właściwości tej klasy, które umożliwiają sprawną obsługę wyjątków.

  • ExceptionType – Jest to typ obsługiwanego wyjątku. Domyślnie są obsługiwane są wszystkie standardowe wyjątki.
  • View – Nazwa szablonu widoku generowanego przez filtr. Jeśli pominiemy ten parametr to domyślenie będzie generowany widok z lokalizacji /Views/<nazwa kontrolera>/Error.cshtml albo /Views/Shared/Error.cshtml
  • Master -Nazwa układu z który będzie używany przy generowaniu wyniku filtru.

 Ważna uwaga: HandleErrorAttribute działa tylko wtedy gdy w web.confg-u ustawimy niestandardową obsługę wyjątków – sekcja <system.web> <customErrors mode=”On”>

Poniżej kod, którego działanie jest identyczne z tym przedstawionym powyżej ale przy zastosowaniu HandleErrorAttribute.

[HandleError(ExceptionType=typeof(NullReferenceException), View="BrakStrony")]

Trochę prościej i trochę szybciej. Jedyną zmianą, którą nalezy dokonać to zmiany w widoku.