Comment retourner une vue pour HttpNotFound () dans ASP.Net MVC 3?

Existe-t-il un moyen de retourner la même vue chaque fois qu’un HttpNotFoundResult est renvoyé par un contrôleur? Comment spécifiez-vous cette vue? Je suppose que la configuration d’une page 404 dans le fichier web.config pourrait fonctionner, mais je voulais savoir s’il y avait un meilleur moyen de gérer ce résultat.

Edition / Suivi:

J’ai fini par utiliser la solution trouvée dans la deuxième réponse à cette question avec quelques légères modifications pour qu’ASP.Net MVC 3 gère mes 404: Comment gérer correctement les 404 dans ASP.Net MVC?

HttpNotFoundResult ne rend pas une vue. Il définit simplement le code d’état à 404 et renvoie un résultat vide utile pour AJAX, mais si vous voulez une page d’erreur 404 personnalisée, vous pouvez throw new HttpException(404, "Not found") qui affichera automatiquement la vue configurée. Web.config:

    

Cette solution combine IResultFilter et IExceptionFilter pour intercepter soit une exception HttpException levée, soit un HttpStatusCodeResult renvoyé dans une action.

 public class CustomViewForHttpStatusResultFilter: IResultFilter, IExceptionFilter { ssortingng viewName; int statusCode; public CustomViewForHttpStatusResultFilter(HttpStatusCodeResult prototype, ssortingng viewName) : this(prototype.StatusCode, viewName) { } public CustomViewForHttpStatusResultFilter(int statusCode, ssortingng viewName) { this.viewName = viewName; this.statusCode = statusCode; } public void OnResultExecuted(ResultExecutedContext filterContext) { HttpStatusCodeResult httpStatusCodeResult = filterContext.Result as HttpStatusCodeResult; if (httpStatusCodeResult != null && httpStatusCodeResult.StatusCode == statusCode) { ExecuteCustomViewResult(filterContext.Controller.ControllerContext); } } public void OnResultExecuting(ResultExecutingContext filterContext) { } public void OnException(ExceptionContext filterContext) { HttpException httpException = filterContext.Exception as HttpException; if (httpException != null && httpException.GetHttpCode() == statusCode) { ExecuteCustomViewResult(filterContext.Controller.ControllerContext); // This causes ELMAH not to log exceptions, so commented out //filterContext.ExceptionHandled = true; } } void ExecuteCustomViewResult(ControllerContext controllerContext) { ViewResult viewResult = new ViewResult(); viewResult.ViewName = viewName; viewResult.ViewData = controllerContext.Controller.ViewData; viewResult.TempData = controllerContext.Controller.TempData; viewResult.ExecuteResult(controllerContext); controllerContext.HttpContext.Response.TrySkipIisCustomErrors = true; } } 

Vous pouvez enregistrer ce filtre en spécifiant le code d’état HTTP de HttpException ou le HttpStatusCodeResult concret pour lequel vous souhaitez afficher la vue personnalisée.

 GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(new HttpNotFoundResult(), "Error404")); // alternate syntax GlobalFilters.Filters.Add(new CustomViewForHttpStatusResultFilter(404, "Error404")); 

Il gère les exceptions et HttpStatusCodeResult lancées ou renvoyées dans une action. Il ne gérera pas les erreurs qui surviennent avant que MVC ne sélectionne une action et un contrôleur appropriés, comme ceci:

  • Itinéraires inconnus
  • Contrôleurs inconnus
  • Actions inconnues

Pour gérer ces types d’erreurs NotFound, combinez cette solution avec d’ autres solutions que vous trouverez dans stackoverflow.

Informations utiles de @Darin Dimitrov que HttpNotFoundResult retourne en fait un résultat vide.

Après quelques études. La solution de contournement pour MVC 3 consiste à dériver toutes les HttpNotFoundResult , HttpUnauthorizedResult , HttpStatusCodeResult et à implémenter la nouvelle méthode HttpNotFound () dans BaseController .

Il est recommandé d’utiliser le contrôleur de base afin de contrôler tous les contrôleurs dérivés.

Je crée une nouvelle classe HttpStatusCodeResult , non pour dériver d’ ActionResult mais de ViewResult pour afficher la vue ou toute View souhaitée en spécifiant la propriété ViewName . Je suis le HttpStatusCodeResult origine pour définir le HttpContext.Response.StatusCode et le HttpContext.Response.StatusDescription mais base.ExecuteResult(context) affichera alors la vue appropriée car je dérive à nouveau de ViewResult . Assez simple est-ce? J’espère que cela sera implémenté dans le kernel MVC.

Voir ci-dessous mon BaseController :

 using System.Web; using System.Web.Mvc; namespace YourNamespace.Controllers { public class BaseController : Controller { public BaseController() { ViewBag.MetaDescription = Settings.metaDescription; ViewBag.MetaKeywords = Settings.metaKeywords; } protected new HttpNotFoundResult HttpNotFound(ssortingng statusDescription = null) { return new HttpNotFoundResult(statusDescription); } protected HttpUnauthorizedResult HttpUnauthorized(ssortingng statusDescription = null) { return new HttpUnauthorizedResult(statusDescription); } protected class HttpNotFoundResult : HttpStatusCodeResult { public HttpNotFoundResult() : this(null) { } public HttpNotFoundResult(ssortingng statusDescription) : base(404, statusDescription) { } } protected class HttpUnauthorizedResult : HttpStatusCodeResult { public HttpUnauthorizedResult(ssortingng statusDescription) : base(401, statusDescription) { } } protected class HttpStatusCodeResult : ViewResult { public int StatusCode { get; private set; } public ssortingng StatusDescription { get; private set; } public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { } public HttpStatusCodeResult(int statusCode, ssortingng statusDescription) { this.StatusCode = statusCode; this.StatusDescription = statusDescription; } public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } context.HttpContext.Response.StatusCode = this.StatusCode; if (this.StatusDescription != null) { context.HttpContext.Response.StatusDescription = this.StatusDescription; } // 1. Uncomment this to use the existing Error.ascx / Error.cshtml to view as an error or // 2. Uncomment this and change to any custom view and set the name here or simply // 3. (Recommended) Let it commented and the ViewName will be the current controller view action and on your view (or layout view even better) show the @ViewBag.Message to produce an inline message that tell the Not Found or Unauthorized //this.ViewName = "Error"; this.ViewBag.Message = context.HttpContext.Response.StatusDescription; base.ExecuteResult(context); } } } } 

Pour utiliser dans votre action comme ceci:

 public ActionResult Index() { // Some processing if (...) return HttpNotFound(); // Other processing } 

Et dans _Layout.cshtml (comme la page maître)

 
@if (ViewBag.Message != null) {

@ViewBag.Message

} @RenderBody()

De plus, vous pouvez utiliser une vue personnalisée comme Error.shtml ou créer un nouveau NotFound.cshtml comme je l’ai NotFound.cshtml dans le code et définir un modèle de vue pour la description du statut et d’autres explications.

 protected override void HandleUnknownAction(ssortingng actionName) { ViewBag.actionName = actionName; View("Unknown").ExecuteResult(this.ControllerContext); } 

Voici la vraie réponse qui permet de personnaliser entièrement la page d’erreur en un seul endroit. Pas besoin de modifier web.confiog ou de créer des classes et du code sophistiqués. Fonctionne également dans MVC 5.

Ajoutez ce code au contrôleur:

  if (bad) { Response.Clear(); Response.TrySkipIisCustomErrors = true; Response.Write(product + I(" Toodet pole")); Response.StatusCode = (int)HttpStatusCode.NotFound; //Response.ContentType = "text/html; charset=utf-8"; Response.End(); return null; } 

Basé sur http://www.eidias.com/blog/2014/7/2/mvc-custom-error-pages

Veuillez suivre ceci si vous voulez une erreur httpnotfound dans votre contrôleur

  public ActionResult Contact() { return HttpNotFound(); }