2009-07-23 11 views
5

Ho un asp.net MVC 1.0 che serve alcuni contenuti da una gerarchia di livelli 2 /categoria/articoloCome gestire 'View not found' InvalidOperationException in asp.net mvc?

Quando le cose vanno bene al mappe di articolo per una vista e lo sguardo si rese. Tuttavia, quando l'url soddisfa la condizione di routing ma la vista non esiste, viene sollevata un'eccezione che non è possibile intercettare nell'azione Controller.

Routing:

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

MyController Azione:

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

Tuttavia, quando la vista non viene trovato, un System.InvalidOperationException viene generato che non posso prendere in azione Controller.

Dettagli eccezione: System.InvalidOperationException: La vista '~/Vista/my-category/my-articolo-con-lungo name.aspx' o il suo padrone non è stato trovato. Le seguenti posizioni sono stati cercati: ~/Vista/my-category/my-articolo-con-lungo name.aspx

posso intercettare l'errore nel metodo Application_Error() in global.asax.cs ma:

  1. non so come reindirizzare alla vista errori da lì
  2. chiedo se c'è un posto migliore più vicino a dove è sollevata l'eccezione .

risposta

7

xandy, Greg, Apprezzo le tue risposte. Questo articolo (Strategies For Resource Based 404 Errors in aspnet mvc) mi ha aiutato a ricavare la soluzione che stavo cercando in un modo abbastanza pulito. Tutto quello che devo fare è sovrascrivere Controller.OnException. Dal momento che ho un solo controller in cui ho bisogno del comportamento, devo solo sovrascrivere OnException in quel controller.

Detto questo, la mia soluzione tratta i sintomi non la malattia e, come suggeriscono entrambi, sarebbe meglio controllare l'esistenza del file prima di invocarlo. Vedi su un percorso.

Ecco il codice che ho usato per trattare i sintomi :)

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); 
} 

Un problema non riuscivo a risolvere è come visualizzare il NotFound View in modo pulito. Di solito si accede tramite l'azione NotFound ErrorController. Ho dovuto hardcode il percorso ad esso. Posso vivere con questo ma vorrei sapere se è possibile senza il percorso HC.

+0

Ho provato e mi piace la soluzione. L'unico problema è che se si ottiene un InvalidOperationException a causa di un diverso motivo, si verificherà un 404. Ho avuto un'eccezione simile quando provavo a serializzare qualcosa. – Bealer

0

Penso che il posto migliore per verificare se la vista esiste sarebbe all'interno del controller. Se incapsulate il costruttore della vista non funziona, allora potrebbe essere l'ASP.net posticipare l'istanza di Vista all'esterno del costruttore (non è sicuro se lo sia).

Ma una cosa che si potrebbe provare è controllare manualmente e vedere se il percorso esiste o no, utilizzando Server.MapPath() per ottenere il percorso assoluto del file e verificare se è esistente.

0

Vorrei solo restituire una vista predefinita, forse sarebbe una risposta 404 appropriata. Ovviamente per farlo funzionare, dovrai cambiare un po 'la tua architettura.

AFAIK è necessario disporre di codice per verificare se il file esiste, come nel file ASPX se non si desidera il comportamento predefinito del framework. Potrebbe essere necessario utilizzare ResolveURL or Url.Content per risolvere il percorso dal percorso dell'applicazione.

Come nota, in generale, non è esattamente sicuro rendere il dominio (i nomi dei file) esposto al mondo. Se gli ASPX sono solo dati, allora dovresti inserire il testo in un database o in semplici file di testo non eseguibili. Se stai costruendo una sorta di CMS (cioè vuoi davvero un modo di 'installare' funzionalità), allora potresti prendere in considerazione l'utilizzo di una vista ASPX per contenere viste parziali per incapsulare i blocchi del codice ASP.NET.

Per quanto riguarda il passaggio alla pagina 404, this answer potrebbe essere d'aiuto.

3

C'è un posto adatto per gestire questo. Se si implementa il proprio ViewEngine, è possibile sovrascrivere il metodo "FileExists".

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

     return true; 
    } 

}

Hai solo bisogno di registrare il motore di visualizzazione in Global.asax in questo modo,

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

In Application_Error è possibile implementare un gestore che cattura NotFoundExceptions, li registra, poi restituisce un messaggio amichevole tramite l'esecuzione di un ErrorController.