2009-07-23 9 views
5

J'ai un site 1.0 mvc asp.net qui sert une partie du contenu d'une hiérarchie de niveau 2 /catégorie/articleComment gérer 'View not found' InvalidOperationException dans asp.net mvc?

Quand les choses fonctionnent correctement les cartes d'article à vue et la vue obtient rendu. Toutefois, lorsque l'URL rencontre la condition de routage mais la vue n'existe pas, une exception est levée que je ne peux pas intercepter dans l'action Contrôleur.

Routing:

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

MyController Action:

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

Cependant, lorsque la vue ne se trouve pas, un System.InvalidOperationException est généré que je ne peux pas attraper dans l'action du contrôleur.

Détails de l'exception: System.InvalidOperationException: La vue '~/Vues/my-catégorie/my-article-avec-long name.aspx' ou son maître n'a pas pu être trouvé. Les endroits suivants ont été recherchées: ~/Vues/my-catégorie/my-article-avec-long name.aspx

je peux intercepter l'erreur dans la méthode Application_Error() dans global.asax.cs mais:

  1. ne savent pas comment rediriger à la vue d'erreur à partir de là
  2. je me demande s'il y a un meilleur endroit plus proche de l'endroit où l'exception est soulevée .

Répondre

7

xandy, Greg, Je vous remercie de vos réponses. Cet article (Strategies For Resource Based 404 Errors in aspnet mvc) m'a aidé à dériver la solution que je cherchais d'une manière plutôt propre. Tout ce que j'ai besoin de faire est de remplacer le contrôleur.OnException. Puisque j'ai seulement un contrôleur où j'ai besoin du comportement je dois seulement remplacer OnException dans ce contrôleur. Cela étant dit, ma solution traite les symptômes et non la maladie et comme vous le suggérez tous les deux, il serait préférable de vérifier l'existence du fichier avant de l'invoquer. Vue sur un chemin.

Voici le code je pour traiter les symptômes :)

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 problème que je ne pouvais pas résoudre est comment afficher la NotFound Voir de manière propre. Il est généralement accessible via l'Action NotFound ErrorController. J'ai dû coder en dur le chemin. Je peux vivre avec cela mais je voudrais savoir si c'est possible sans le chemin HC.

+0

J'ai essayé et aimé la solution. Le seul problème est que si vous obtenez une exception InvalidOperationException pour une raison différente, il en résultera un 404. Une telle exception s'est produite lors de la tentative de sérialisation de quelque chose. – Bealer

0

Je pense que le meilleur endroit pour vérifier si la vue existe serait dans le contrôleur. Si vous encapsulez le constructeur de la vue ne fonctionne pas, alors il pourrait être le ASP.net reporter l'instanciation de vue à l'extérieur du constructeur (pas sûr si elle est).

Mais une chose que vous pouvez essayer est de vérifier manuellement et de voir si le chemin existe ou non, en utilisant Server.MapPath() pour obtenir le chemin absolu du fichier et vérifier s'il existe.

0

Je voudrais juste revenir une vue par défaut, peut-être une réponse 404 serait appropriée. Bien sûr, pour que cela fonctionne, vous devrez changer votre architecture un peu. Je pense que vous aurez besoin d'avoir du code pour vérifier si le fichier existe, comme dans votre fichier ASPX si vous ne voulez pas le comportement de l'infrastructure par défaut. Vous devrez peut-être utiliser ResolveURL or Url.Content pour résoudre le chemin à partir de votre chemin d'application.

Comme une note, en général, il est pas tout à fait sûr de rendre votre domaine (les noms de fichiers) exposés au monde. Si les ASPX ne sont que des données, vous devez placer le texte dans une base de données ou dans des fichiers texte non exécutables. Si vous construisez une sorte de CMS (c'est-à-dire que vous voulez vraiment une méthode d'installation), alors vous pourriez envisager d'utiliser une vue ASPX pour contenir des vues partielles pour encapsuler les morceaux de code ASP.NET.

Comme pour se rendre à la page 404, this answer pourrait aider.

3

Il existe un endroit approprié pour gérer cela. Si vous implémentez votre propre ViewEngine, vous pouvez remplacer la méthode "FileExists".

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

     return true; 
    } 

}

Vous avez juste besoin d'enregistrer le moteur d'affichage dans votre Global.asax comme si,

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

En Application_Error vous pouvez implémenter un gestionnaire qui attire NotFoundExceptions, les journaux, puis renvoie un message convivial via l'exécution d'un ErrorController.

Questions connexes