J'ai enquêté A LOT sur la façon de gérer correctement les 404 dans MVC (spécifiquement MVC3) et ceci, à mon avis, est la meilleure solution que j'ai trouvée :
Dans global.asax :
public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}
ErreursContrôleur :
public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;
object model = Request.Url.PathAndQuery;
if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);
return result;
}
}
Edit :
Si vous utilisez IoC (par exemple AutoFac), vous devez créer votre contrôleur en utilisant :
var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);
Au lieu de
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
(facultatif)
Explication :
Il y a 6 scénarios auxquels je peux penser où une application ASP.NET MVC3 peut générer des 404s.
Généré par ASP.NET :
-
Scénario 1 : L'URL ne correspond pas à une route dans la table des routes.
Généré par ASP.NET MVC :
-
Scénario 2 : L'URL correspond à une route, mais spécifie un contrôleur qui n'existe pas.
-
Scénario 3 : L'URL correspond à un itinéraire, mais spécifie une action qui n'existe pas.
Généré manuellement :
-
Scénario 4 : Une action renvoie un HttpNotFoundResult en utilisant la méthode HttpNotFound().
-
Scénario 5 : Une action déclenche une HttpException avec le code d'état 404.
-
Scénario 6 : Une action modifie manuellement la propriété Response.StatusCode en 404.
Objectifs
-
(A) Afficher une page d'erreur 404 personnalisée à l'utilisateur.
-
(B) Maintenez le code d'état 404 sur la réponse du client (particulièrement important pour le référencement).
-
(C) Envoyez la réponse directement, sans impliquer une redirection 302.
Tentative de solution : Erreurs personnalisées
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customErrors>
</system.web>
Problèmes avec cette solution :
- Ne respecte pas l'objectif (A) dans les scénarios (1), (4), (6).
- Ne répond pas automatiquement à l'objectif (B). Il doit être programmé manuellement.
- Ne répond pas à l'objectif (C).
Tentative de solution : Erreurs HTTP
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problèmes avec cette solution :
- Ne fonctionne que sur IIS 7+.
- Ne respecte pas l'objectif (A) dans les scénarios (2), (3), (5).
- Ne répond pas automatiquement à l'objectif (B). Il doit être programmé manuellement.
Tentative de solution : Erreurs HTTP avec remplacement
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problèmes avec cette solution :
- Ne fonctionne que sur IIS 7+.
- Ne répond pas automatiquement à l'objectif (B). Il doit être programmé manuellement.
- Il masque les exceptions http au niveau de l'application. Par exemple, on ne peut pas utiliser la section customErrors, System.Web.Mvc.HandleErrorAttribute, etc. Il ne peut pas afficher uniquement les pages d'erreur génériques.
Solution Attempt customErrors et HTTP Errors
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
et
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problèmes avec cette solution :
- Ne fonctionne que sur IIS 7+.
- Ne répond pas automatiquement à l'objectif (B). Il doit être programmé manuellement.
- Ne respecte pas l'objectif (C) dans les scénarios (2), (3), (5).
Les personnes qui ont déjà eu des problèmes avec cela ont même essayé de créer leurs propres bibliothèques (cf. http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). Mais la solution précédente semble couvrir tous les scénarios sans la complexité de l'utilisation d'une bibliothèque externe.
1 votes
Voici une bonne lecture sur ce sujet @ Comment gérer efficacement les erreurs 404 Not Found avec ASP.NET MVC 4