2009-07-23 8 views
5

Mam ASP.NET MVC 1.0, która serwuje jakieś treści z 2 hierarchii poziom /kategorii/artykułJak obsłużyć polecenie "Nie znaleziono" InvalidOperationException w asp.net mvc?

Kiedy wszystko działa prawo mapy artykuł do widzenia, a widok zostanie wygenerowana. Jednakże, gdy adres URL spełnia warunek routingu, ale widok nie istnieje, zgłaszany jest wyjątek, którego nie można przechwycić w działaniu kontrolera.

Routing:

routes.MapRoute(
    "Article", 
    "{category}/{article}.aspx", 
    new { controller = "MyController", action = "Article" } 
); 

MyController Działanie:

public ActionResult Article(string category, string article) 
{ 
    string path = string.Format("~/Views/{0}/{1}.aspx", category, article); 
    ViewResult vr = View(path); 
    return vr; 
} 

Jednak, gdy widok nie zostanie znaleziony, System.InvalidOperationException generowany jest, że nie mogę złapać w działaniu sterownika.

Szczegóły wyjątku: System.InvalidOperationException: widok '~/Views/my-kategoria/my-Art-z-długim name.aspx' nie można znaleźć lub jego mistrza . Poniższe lokalizacje były wyszukiwane: ~/Views/my-kategoria/my-Art-z-długim name.aspx

mogę pułapka błąd w metodzie Application_Error() w global.asax.cs ale:

  1. Nie wiem, jak przekierować do widoku błędu stamtąd
  2. Zastanawiam się, czy istnieje lepsze miejsce bliżej miejsca, w którym został zgłoszony wyjątek .

Odpowiedz

7

xandy, Greg, Doceniam twoje odpowiedzi. Ten artykuł (Strategies For Resource Based 404 Errors in aspnet mvc) pomógł mi znaleźć rozwiązanie, którego szukałem w całkiem czysty sposób. Wszystko, co muszę zrobić, to przesłonić kontroler.OnException. Ponieważ mam tylko jeden kontroler, w którym potrzebuję zachowania, muszę tylko przesłonić wyjątek OnException w tym kontrolerze.

To powiedziawszy, moje rozwiązanie traktuje symptomy, a nie chorobę i jak obaj sugerujesz, byłoby lepiej sprawdzić istnienie pliku przed wywołaniem tego. Zobacz na ścieżce.

Oto kod I stosuje się w leczeniu objawów :)

protected override void OnException(ExceptionContext filterContext) 
{ 
    //InvalidOperationException is thrown if the path to the view 
    // cannot be resolved by the viewengine 
    if (filterContext.Exception is InvalidOperationException) 
    { 
     filterContext.ExceptionHandled = true; 
     filterContext.Result = View("~/Views/Error/NotFound.aspx"); 
     filterContext.HttpContext.Response.StatusCode = 404; 
    } 

    base.OnException(filterContext); 
} 

Jedna kwestia nie mogę rozwiązać ten sposób, aby wyświetlić NOTFOUND View w czystym sposób. Zwykle uzyskuje się do niego dostęp za pomocą akcji ErrorController NotFound. Musiałem skasować ścieżkę do niego. Mogę z tym żyć, ale chciałbym wiedzieć, czy jest to możliwe bez ścieżki HC.

+0

Próbowałem i podoba mi się rozwiązanie. Jedynym problemem jest to, że jeśli otrzymasz wyjątek InvalidOperationException z innego powodu, spowoduje to 404. Wystąpił taki wyjątek, gdy próbuję serializować coś. – Bealer

0

Myślę, że najlepszym miejscem do sprawdzenia, czy widok istnieje w kontroler. Jeśli enkapsulacja konstruktora widoku nie działa, to może to być ASP.net odroczyć instancję View poza konstruktorem (nie wiem, czy jest).

Ale możesz spróbować ręcznie sprawdzić, czy ścieżka istnieje, czy nie, używając Server.MapPath(), aby uzyskać bezwzględną ścieżkę do pliku i sprawdzić, czy istnieje.

0

Po prostu zwrócę domyślny widok, być może odpowiednia będzie odpowiedź 404. Oczywiście, aby to zadziałało, musisz nieco zmienić swoją architekturę.

AFAIK musisz mieć kod do sprawdzenia, czy plik istnieje, jak w twoim pliku ASPX, jeśli nie chcesz domyślnego zachowania struktury. Możesz użyć ResolveURL or Url.Content, aby usunąć ścieżkę ze ścieżki aplikacji.

Ogólnie rzecz biorąc, nie jest całkiem bezpiecznie udostępnienie swojej domeny (nazw plików) światu. Jeśli ASPX to tylko dane, powinieneś umieścić tekst w bazie danych lub zwykłych, niewykonywalnych plikach tekstowych. Jeśli budujesz jakiś CMS (tzn. Naprawdę chcesz mieć sposób "instalowania" funkcjonalności), możesz rozważyć użycie widoku ASPX, aby zawierał częściowe widoki do enkapsulacji fragmentów kodu ASP.NET.

Pomoc w uzyskaniu dostępu do strony 404: this answer.

3

Istnieje odpowiednie miejsce do obsługi tego. Jeśli zaimplementujesz własny ViewEngine, możesz zastąpić metodę "FileExists".

public class ViewEngine : RazorViewEngine 
{ 
    protected override bool FileExists(ControllerContext context, string path) 
    { 
     if(!base.FileExists(context, path)) 
      throw new NotFoundException(); 

     return true; 
    } 

}

Wystarczy zarejestrować silnik widok w Global.asax jak tak,

ViewEngines.Engines.Clear(); 
ViewEngines.Engines.Add(new ViewEngine()); 

W Application_Error można zaimplementować obsługi, że połowy NotFoundExceptions, rejestruje je, a następnie zwraca przyjazną wiadomość poprzez wykonanie ErrorController.

Powiązane problemy