2012-12-12 17 views
11

Gdy wystąpi błąd w mojej aplikacji ASP.NET MVC 4, chciałbym dostosować widok dla użytkownika w zależności od rodzaju błędu. Na przykład strona nie została znaleziona lub wystąpił wyjątek (z pewnymi przyjaznymi dla użytkownika szczegółami dotyczącymi wyjątku). Sprawdziłem inne przykłady tego, jak to zrobić w StackOverflow i innych źródłach internetowych, ale żadna z odpowiedzi nie działa dla mnie.ASP.NET MVC 4 - Obsługa wyjątków nie działa

Podstawowy atrybut [HandleError] prawdopodobnie nie działa w VS2012 z aplikacją MVC 4 targetującą .NET 4.5. Oto kod mam w moim kontrolera głównego:

[HandleError] 
public ActionResult Index() 
{ 
    Response.TrySkipIisCustomErrors = true; //doesn't work with or without this 
    throw new NullReferenceException("Uh oh, something broke."); 
} 

To jest po prostu rzuca wyjątek, a spodziewałbym widok domyślny ~/Shared/Error.cshtml być zwrócone z powodu [HandleError] atrybutu ale dostaję tylko wewnętrzny błąd serwera HTTP 500 wskazujący, że strona nie mogła zostać wyświetlona. Sprawdziłem mój web.config i różne konfiguracje wydają się dziwnie zachowywać. W sekcji tej chwili zawiera:

<customErrors mode="On" /> 

(Próbowałem dodanie defaultRedirect iz trybie CustomErrors = „Off”, jak dobrze, ale to nie ma żadnego wpływu ... ani wspólny pogląd o błędzie lub Widok CustomError jest renderowany. Jeśli zmienię tryb customErrors na wyłączony, wtedy widzę szczegóły wyjątku zgodnie z oczekiwaniami, więc poprawnie zgłaszam wyjątek "Uh oh, coś złamanego". dodanie do programu HomeController procedury obsługi wyjątku OnException i chociaż mogę przeprowadzić debugowanie i zobaczyć, że zdarzenie OnException jest podnoszone, nie ma to znaczenia:

protected override void OnException(ExceptionContext filterContext) 
{ 
    base.OnException(filterContext); 
    filterContext.ExceptionHandled = true; 
    if (filterContext == null) 
    { 
     filterContext.Result = View("CustomError"); 
     return; 
    } 
    Exception e = filterContext.Exception; 
    // TODO: Log the exception here 
    ViewData["Exception"] = e; // pass the exception to the view 
    filterContext.Result = View("CustomError"); 
} 

Próbowałem również zmianę [HandleError], aby określić widok, ale to nie wydaje się robić nic albo:

[HandleError(View="CustomError")] 

Każda pomoc będzie mile widziane. Daj mi znać, jeśli potrzebujesz więcej informacji.

Odpowiedz

4

Przypominam sobie, że trzeba było wywołać stronę z adresu IP innego niż localhost (zwykle innego komputera). I musi to być serwer oparty na IIS, a nie wbudowany serwer programistyczny (a więc IIS lub IIS Express, ale musisz skonfigurować IIS Express dla dostępu zewnętrznego, co jest uciążliwe).

W rzeczywistości można go debugować, należy skonfigurować serwer lokalny na komputerze debugowania, aby zaakceptować żądania zewnętrzne, a następnie zadzwonić do lokalnego serwera ze zdalnego serwera.

+1

Mimo że nie używam 'RemoteOnly' w dowolnym miejscu w web.config, mój oryginalny kod zdaje się działać zdalnie, tylko nie lokalnie! To bardzo mnie zaskakuje. Musiałem dodać '' w sekcji '' pliku web.config, aby widoki mogły być renderowane, ale wydaje się to normalne. Utrudnia to debugowanie lokalnie i wydaje się być błędem, ponieważ 'mode = RemoteOnly' nie jest używany. Jeśli ktokolwiek dowie się, jak uruchomić to na miejscu, daj mi znać. (Mogę w szczególności otworzyć drugie pytanie). –

1

spróbuj dodać następujący atrybut do tagu customErrors:

defaultRedirect="Error" 

ta wyraźnie określa, do której należy przeglądać MVC przekierować użytkownika, gdy zostanie zgłoszony błąd i nie widok jest określony domyślnie w atrybucie. To oczywiście zadziała tylko wtedy, gdy Error.cshtml istnieje w folderze widoków Shared.

+0

W końcu udało mi się rozwiązać te sugestie. Wygląda na to, używając '' zwrócił moją stronę błędu PageNotFound zamiast treści z udostępnionego widoku błędu i nie było żadnych danych wyjątków w ViewData. Myślałem, że to dlatego, że/Error nie istnieje na serwerze, a web.config nie wie nic o rzeczywistych widokach ... ale kiedy zmodyfikowałem procedurę obsługi OnException, aby użyć widoku "Error", to spowodował ten sam błąd HTTP 500, który widziałem od samego początku, i nie widzę już strony PageNotFound. :( –

5

Udałem się również w nieskończoną podróż do czytania odpowiedzi na pytania i różne wpisy na blogu, próbując uzyskać niestandardowe strony błędów do pracy. Poniżej znajduje się to, co w końcu udało się dla mnie.

Pierwszym krokiem jest użycie IIS Express do debugowania zamiast wbudowanego serwera WWW Cassini, aby "zagwarantować", że doświadczenie debugowania będzie odzwierciedlać środowisko na żywo.

Utwórz kontroler, aby obsłużyć błędy aplikacji i dodaj akcję dla każdego niestandardowego błędu, który sobie poradzisz. Akcja powinna wykonać dowolne rejestrowanie, ustawić kod statusu i zwrócić widok.

public class ErrorsController : Controller 
{ 
    // 404 
    [HttpGet] 
    public ActionResult NotFound() 
    { 
     Response.StatusCode = (int)HttpStatusCode.NotFound; 
     return View(); 
    } 

    // I also have test actions so that I can verify it's working in production. 
    [HttpGet] 
    public ActionResult Throw404() 
    { 
     throw new HttpException((int)HttpStatusCode.NotFound, "demo"); 
    } 
} 

Konfiguracja sekcji w web.config customErrors przekierować do niestandardowych działań błędach.

<system.web> 
    <customErrors mode="RemoteOnly" defaultRedirect="Errors/InternalServerError"> 
     <error statusCode="400" redirect="Errors/BadRequest" /> 
     <error statusCode="403" redirect="Errors/Forbidden" /> 
     <error statusCode="404" redirect="Errors/NotFound" /> 
     <error statusCode="500" redirect="Errors/InternalServerError" /> 
    </customErrors> 

Dodaj sekcję httpErrors do system.webServer i ustawić errorMode do szczegółowa w web.config. Dlaczego to działa jest dla mnie zagadką, ale to był klucz.

<system.webServer> 
    <httpErrors errorMode="Detailed" /> 

Dodaj trasę catchall do zdefiniowanych tras, aby przekierować 404 do strony niestandardowej.

  // catchall for 404s 
     routes.MapRoute(
      "Error", 
      "{*url}", 
      new {controller = "Errors", action = "NotFound"}); 

Można też utworzyć niestandardowy HandleErrorAttribute i zarejestrować go jako filtr globalnej zalogowania 500 błędów.

Te kroki sprawdziły się w środowiskach programistycznych (IIS Express) i produkcyjnych (IIS7). Musisz zmienić customErrors mode="On", aby zobaczyć efekt w rozwoju.

+0

Sprawdziłem i od Właściwości projektu> Web, domyślnie było "Użyj lokalnego serwera IIS Web" z zaznaczonym IIS Express.To zajmie mi trochę, aby sprawdzić resztę. –

+1

Po usunięciu mojej catch-all route dla 404-tych , modyfikując web.config, tworząc ErrorsController i podpinając trasy Errors/{Action}, wydaje się, że nie działa zgodnie z oczekiwaniami. To tak, jakby serwer IIS nie przekierowywał poprawnie do Errors/, gdy ten status Pojawiają się kody: Nawiguję do /Błędy/, działa, ale nie otrzymuję strony niestandardowej po ustawieniu 'Response.StatusCode' .Jeśli usunę kod stanu, to otrzymam stronę niestandardową, ale nie robi" t wyzwalanie na innych nie znaleziono ścieżek lub wyjątków (/blah) .Spróbowałem lokalnie i zdalnie. –

+0

Jeśli przyczyną nie są przekierowania, to takie podejście może być wykonalne (ex cept, że może nie być w stanie przekazać faktycznego wyjątku do widoku InternalServerError w celu wyświetlenia niestandardowych stron błędów, jeśli jest to potrzebne). –

1

Zmierzyłem się z podobnym problemem i zagubiłem się kiedyś, próbując ustalić, co się dzieje. Tak więc na wypadek, gdyby inni mieli podobny problem, oto mój problem.

Strona błędu próbowała użyć mojej strony _Layout. Po prostu upewnij się, że strona Error.cshtml ma

@ { Layout = null; }