2013-06-11 23 views
20

Kiedy wyjątek jest wywoływany przez własny kod wywoływany z działania kontrolera, w jaki sposób należy go obsłużyć? Widzę wiele przykładów najlepszych praktyk, w których nie ma żadnych instrukcji try-catch. Na przykład, dostęp do danych z repozytorium:Obsługa wyjątków w kontrolerze (ASP.NET MVC)

public ViewResult Index() 
{ 
    IList<CustomModel> customModels = _customModelRepository.GetAll(); 
    return View(customModels); 
} 

Oczywiście ten kod może rzucić wyjątek, jeśli połączenie jest do bazy danych, która nie ma dostępu i korzystania z Entity Framework ORM jak np.

Jednak wszystko, co mogę zobaczyć, stanie się faktem, że wyjątek pojawi się i wyświetli nieprzyjemny komunikat o błędzie dla użytkownika.

Jestem świadomy atrybutu HandleError, ale rozumiem, że jest używany głównie do przekierowania do strony błędu, jeśli wystąpi wyjątek, który jest nieobsługiwany.

Oczywiście, ten kod może być owinięty w try-catch, ale nie oddzielają ładnie, zwłaszcza jeśli masz więcej logiki:

public ViewResult Index() 
{ 
    if (ValidationCheck()) 
    { 
     IList<CustomModel> customModels = new List<CustomModel>(); 
     try 
     { 
      customModels = _customModelRepository.GetAll(); 
     } 
     catch (SqlException ex) 
     { 
      // Handle exception 
     } 

     if (CustomModelsAreValid(customModels)) 
      // Do something 
     else 
      // Do something else 
    } 

    return View(); 
} 

Wcześniej zostały wyodrębnione wszystkie kod, który mógłby rzucić wyjątki, takie jak wywołania bazy danych do klasy DataProvider, która obsługuje błędy i odsyła wiadomości w celu wyświetlenia komunikatów dla użytkownika.

Zastanawiałem się, jaki jest najlepszy sposób, aby to zrobić? Nie zawsze chcę powracać do strony błędu, ponieważ niektóre wyjątki nie powinny tego robić. Zamiast tego powinien być wyświetlany komunikat o błędzie z normalnym widokiem. Czy moja poprzednia metoda była poprawna lub czy istnieje lepsze rozwiązanie?

Odpowiedz

20

zrobić trzy rzeczy, aby wyświetlić więcej wiadomości przyjazne dla użytkownika:

  1. Skorzystaj z globalnej obsługi wyjątków. W przypadku MVC: Application_Error w Global.asax. Dowiedz się, jak go używać: http://msdn.microsoft.com/en-us/library/24395wz3(v=vs.100).aspx
  2. Podklasa I Wyjątek do wyjątku UserFriendlyException. Robię, co w mojej mocy, we wszystkich moich podstawowych klasach usług, aby rzucić wyjątek UserFriendlyException zamiast zwykłego starego wyjątku. Zawsze staram się umieszczać komunikaty znaczące dla użytkownika w tych niestandardowych wyjątkach. Głównym celem jest umożliwienie sprawdzenia typu na wyjątku w metodzie Application_Error. W UserFriendlyExceptions używam tylko przyjaznej dla użytkownika wiadomości, którą ustawiłem w swoich usługach, np. "Hej! 91 stopni nie jest prawidłową wartością szerokości geograficznej!". Jeśli jest to zwykły wyjątek, to jest to przypadek, który nie został obsłużony, dlatego wyświetlany jest bardziej ogólny komunikat o błędzie, na przykład "Ups, coś poszło nie tak!" Zrobimy co w naszej mocy, aby to naprawić! ".
  3. Tworzę także ErrorController, który jest odpowiedzialny za renderowanie widoków przyjaznych dla użytkownika lub JSON. Jest to kontroler, którego metody będą wywoływane z metody Application_Error.

EDIT: myślałem dałbym wzmiankę do ASP.NET Web API ponieważ jest ściśle związane. Ponieważ konsument punktów końcowych Web API niekoniecznie będzie przeglądarką, lubię zajmować się błędami nieco inaczej. Nadal używam "FriendlyException" (# 2 powyżej), ale zamiast przekierowywania do kontrolera ErrorController, po prostu pozwoliłem wszystkim moim punktom końcowym zwrócić rodzaj bazowy zawierający właściwość Error. Tak więc, jeśli wyjątek pęcznieje aż do kontrolerów Web API, upewniam się, że ten błąd występuje we właściwości Error odpowiedzi API. Ten komunikat o błędzie będzie albo przyjaznym komunikatem, który pojawił się w bąblu na klasach, na których opiera się kontroler API, albo będzie zwykłym komunikatem, jeśli typem wyjątku nie jest FriendlyException. W ten sposób klient zużywający może po prostu sprawdzić, czy właściwość Error odpowiedzi API jest pusta. Wyświetl komunikat, jeśli błąd występuje, postępuj jak zwykle, jeśli nie. Fajną rzeczą jest to, że ze względu na przyjazną koncepcję wiadomości, wiadomość może być znacznie bardziej znacząca dla użytkownika niż ogólny "Błąd!" wiadomość. Korzystam z tej strategii podczas pisania aplikacji mobilnych za pomocą Xamarin, gdzie mogę udostępniać moje C# typy między moich usług internetowych i mojej aplikacji na iOS/Android.

+1

Zgadzam się również z odpowiedzią Patricka Desjardins': nadrzędnymi OnException to świetny sposób na obsługę błędów. Zwłaszcza jeśli znajduje się w kontrolerze bazowym, z którego dziedziczą wszystkie inne kontrolery. – NovaJoe

0

Wszystkie takie pytania nie są zbyt konstruktywne, ponieważ odpowiedź zawsze brzmi "to zależy", ponieważ istnieje wiele sposobów radzenia sobie z błędami.

Wiele osób korzysta z metody HandleError, ponieważ każdy wyjątek jest w zasadzie niemożliwy do odzyskania. Mam na myśli to, co zrobisz, jeśli nie możesz zwrócić przedmiotów? I tak im pokażecie błąd, prawda?

Pytanie brzmi, jak chcesz pokazać im błąd. Jeśli pokazanie im strony błędu jest dopuszczalne, to funkcja HandleError działa dobrze i zapewnia łatwe miejsce do zarejestrowania błędu. Jeśli używasz Ajaxa lub chcesz czegoś bardziej wyszukanego, musisz opracować sposób na zrobienie tego.

Mówisz o klasie DataProvider. Zasadniczo to jest twoje repozytorium. Dlaczego nie zbudujesz tego w swoim repozytorium?

16

Dzięki Asp.Net MVC można również zastąpić metodę OnException dla kontrolera.

protected override void OnException(ExceptionContext filterContext) 
{ 
    if (filterContext.ExceptionHandled) 
    { 
     return; 
    } 
    filterContext.Result = new ViewResult 
    { 
     ViewName = ... 
    }; 
    filterContext.ExceptionHandled = true; 
} 

To pozwala na przekierowanie do niestandardowej strony błędu z komunikatem, który odnosi się do wyjątku, jeśli chcesz.

+0

Obaj spadkowcy kłócą się trochę: co jest nie tak z tą odpowiedzią? – Askolein

+1

@Askolein Nie rozumiem też. Możesz głosować, aby ustawić ponownie na 0, jeśli uważasz, że jest to możliwe, tak jak ja. –

+0

i gotowe ... +1 – Askolein

1

użyłem nadpisanie onException bo mam kilka projektów referenes na taki, który znajduje się kontroler, który obsługiwać błędy:

security/HandleErrorsController.cs

protected override void OnException(ExceptionContext filterContext) 
{ 
    MyLogger.Error(filterContext.Exception); //method for log in EventViewer 

    if (filterContext.ExceptionHandled) 
     return; 

    filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; 

    filterContext.Result = new JsonResult 
    { 
     Data = new 
     { 
      Success = false, 
      Error = "Please report to admin.", 
      ErrorText = filterContext.Exception.Message, 
      Stack = filterContext.Exception.StackTrace 
     }, 
     JsonRequestBehavior = JsonRequestBehavior.AllowGet 
    }; 
    filterContext.ExceptionHandled = true; 
} 
+2

To naprawdę zły pomysł, aby zwracać użytkownikowi surowe treści wyjątków, takie jak wiadomości i ślady stosów. –