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 existait un meilleur moyen de gérer ce résultat.
Editer/Suivre:
J'ai fini par utiliser la solution trouvée dans la deuxième réponse à cette question avec quelques légères modifications pour ASP.Net MVC 3 afin de gérer 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 sur 404 et renvoie un résultat vide, ce qui est utile pour des choses comme AJAX, mais si vous souhaitez une page d'erreur 404 personnalisée, vous pouvez throw new HttpException(404, "Not found")
, ce qui rendra automatiquement l'affichage configuré dans web.config:
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="/Http404.html" />
</customErrors>
Cette solution combine IResultFilter et IExceptionFilter pour intercepter une exception HttpException ou un HttpStatusCodeResult renvoyé depuis une action.
public class CustomViewForHttpStatusResultFilter: IResultFilter, IExceptionFilter
{
string viewName;
int statusCode;
public CustomViewForHttpStatusResultFilter(HttpStatusCodeResult prototype, string viewName)
: this(prototype.StatusCode, viewName) {
}
public CustomViewForHttpStatusResultFilter(int statusCode, string 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 de statut http de l'exception HttpException ou le code concret HttpStatusCodeResult 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 levés ou retournés au sein d'une action. Il ne gérera pas les erreurs qui se produiront avant que MVC ne sélectionne une action appropriée et un contrôleur comme celui-ci:
Pour gérer ces types d’erreurs NotFound, combinez cette solution avec d’autres solutions proposées dans stackoverflow.
Informations utiles de @Darin Dimitrov sur le fait que HttpNotFoundResult
renvoie un résultat vide.
Après quelques études. La solution de contournement pour MVC 3 ici consiste à dériver toutes les classes HttpNotFoundResult
, HttpUnauthorizedResult
, HttpStatusCodeResult
et à mettre en œuvre la méthode new (en le remplaçant) HttpNotFound
() dans BaseController
.
Il est recommandé d’utiliser le contrôleur de base pour pouvoir contrôler tous les contrôleurs dérivés.
Je crée une nouvelle classe HttpStatusCodeResult
, non pas à partir de ActionResult
mais à partir de ViewResult
pour rendre la vue ou toute View
souhaitée en spécifiant la propriété ViewName
. Je suis la HttpStatusCodeResult
d'origine pour définir le HttpContext.Response.StatusCode
et le HttpContext.Response.StatusDescription
, mais base.ExecuteResult(context)
rendra la vue appropriée, car là encore, je dérive de ViewResult
. C'est assez simple? J'espère que cela sera implémenté dans le noyau MVC.
Voir mon BaseController
ci-dessous:
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(string statusDescription = null)
{
return new HttpNotFoundResult(statusDescription);
}
protected HttpUnauthorizedResult HttpUnauthorized(string statusDescription = null)
{
return new HttpUnauthorizedResult(statusDescription);
}
protected class HttpNotFoundResult : HttpStatusCodeResult
{
public HttpNotFoundResult() : this(null) { }
public HttpNotFoundResult(string statusDescription) : base(404, statusDescription) { }
}
protected class HttpUnauthorizedResult : HttpStatusCodeResult
{
public HttpUnauthorizedResult(string statusDescription) : base(401, statusDescription) { }
}
protected class HttpStatusCodeResult : ViewResult
{
public int StatusCode { get; private set; }
public string StatusDescription { get; private set; }
public HttpStatusCodeResult(int statusCode) : this(statusCode, null) { }
public HttpStatusCodeResult(int statusCode, string 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 un gabarit)
<div class="content">
@if (ViewBag.Message != null)
{
<div class="inlineMsg"><p>@ViewBag.Message</p></div>
}
@RenderBody()
</div>
De plus, vous pouvez utiliser une vue personnalisée telle que Error.shtml
ou créer un nouveau NotFound.cshtml
comme je l'ai commenté dans le code et vous pouvez définir un modèle de vue pour la description du statut et d'autres explications.
protected override void HandleUnknownAction(string 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.
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();
}