Routage pour la page d'erreur ASP.NET MVC 404 personnalisée

116

J'essaie de créer une page d'erreur HTTP 404 personnalisée lorsque quelqu'un tape dans une URL qui n'appelle pas une action ou un contrôleur valide dans ASP.NET MVC, au lieu d'afficher l'erreur ASP.NET générique «Ressource introuvable».

Je ne veux pas utiliser web.config pour gérer cela.

Existe-t-il une sorte de magie de routage que je puisse faire pour attraper des URL invalides?

Mise à jour: J'ai essayé la réponse donnée, mais j'obtiens toujours le vilain message "Ressource introuvable".

Une autre mise à jour: Ok, apparemment quelque chose a changé dans RC1. J'ai même essayé de piéger spécifiquement 404 sur un HttpExceptionet cela me donne toujours la page "Ressource introuvable".

J'ai même utilisé la fonctionnalité de ressource de MvcContrib et rien - même problème. Des idées?

dswatik
la source
@Peter C'est la solution que j'ai ajoutée, en plus de remplacer la HandleUnknownAction pour afficher une page introuvable lorsqu'une action n'existe pas, puis le gestionnaire d'erreurs personnalisé ASP.net intégré pour gérer tout ce que les utilisateurs peuvent taper .
dswatik
@pete Cela fonctionne aussi bien stackoverflow.com/questions/619895/…
dswatik
8
Je déteste quand d'autres utilisateurs sont présomptueux et disent des trucs comme, "pourquoi voudriez-vous faire ça? Faites simplement ceci ..." Mais je suggérerais que si rien ne vous empêche d'utiliser l'approche web.config et cela répond à vos besoins, c'est une approche standard et élégante. Toute rétroaction sur cette approche est appréciée, car il pourrait très bien y avoir un problème que je ne connais pas.
Sean

Réponses:

10

Ajoutez simplement la route catch all à la fin de la table des routes et affichez la page de votre choix.

Voir: Comment puis-je créer un itinéraire catch all pour gérer les requêtes «page 404 non trouvée» pour ASP.NET MVC?

Alex Reitbort
la source
J'ai essayé cela cependant, j'obtiens toujours le moche message de ressource par défaut ASP.NET introuvable ..
dswatik
3
Je ne trouve pas de solution définitive (et flexible !!) à ce problème ni dans cette réponse ni sur le lien fourni.
Peter
4
Moi non plus ... cela semble être une sorte de réponse hacky. Je cherche davantage un moyen de faire en sorte que les customErrors se comportent comme ils le font dans WebForms. Des idées?
JC Grubbs
1
Cela ne fonctionne pas et est mauvais en principe. Ne fonctionne pas car il n'attrapera pas les mauvaises URL qui correspondent à l'un des modèles de routage précédents. Mauvais en principe car il convertit ce qui devrait être une erreur en non une erreur. La redirection vers une page que vous avez nommée "Erreur" est différente de la redirection vers une page d'erreur. Vous voulez le conserver comme une erreur, enregistrer l'erreur, puis la traiter comme une erreur. Les erreurs sont des informations précieuses.
Matthew
105

J'ai essayé d'activer les erreurs personnalisées sur le serveur de production pendant 3 heures, il semble que j'ai trouvé la solution finale pour le faire dans ASP.NET MVC sans aucune route.

Pour activer les erreurs personnalisées dans l'application ASP.NET MVC dont nous avons besoin (IIS 7+):

  1. Configurez les pages personnalisées dans la configuration Web sous la system.websection:

    <customErrors mode="RemoteOnly"  defaultRedirect="~/error">
        <error statusCode="404" redirect="~/error/Error404" />
        <error statusCode="500" redirect="~/error" />
    </customErrors>

    RemoteOnlysignifie que sur le réseau local, vous verrez de vraies erreurs (très utiles lors du développement). Nous pouvons également réécrire la page d'erreur pour tout code d'erreur.

  2. Définir le paramètre Magic Response et le code d'état de la réponse (dans le module de gestion des erreurs ou dans l'attribut de gestion des erreurs)

      HttpContext.Current.Response.StatusCode = 500;
      HttpContext.Current.Response.TrySkipIisCustomErrors = true;
  3. Définissez un autre paramètre magique dans la configuration Web sous la system.webServersection:

    <httpErrors errorMode="Detailed" />

C'était la dernière chose que j'ai trouvée et après cela, je peux voir des erreurs personnalisées sur le serveur de production.

Andrew Orsich
la source
8
Ce n'est toujours pas une solution idéale. Il ne vous donne pas les bons codes de réponse HTTP. L'utilisation des customErrorsrésultats dans une redirection 302 juste pour charger votre page d'erreur.
Justin Helgerson
@ Ek0nomik Je n'ai jamais vu de solutions idéales :)
Andrew Orsich
2
@JustinHelgerson J'ai configuré un ErrorController pour chaque code d'état et défini les codes de réponse à l'intérieur de ces actions et il définit les codes de réponse très bien .. J'ai testé avec Fiddler et les codes d'état 404 répondent avec un 404 et les pages avec 500 erreurs répondent avec un 500. Et dans les deux cas, mes vues d'erreur personnalisées sont servies
Shane Neuville
mon coéquipier vient de supprimer la vue d'erreur sous le dossier partagé , pour faire une erreur d'exécution avec un code d'état 500 pour rediriger vers la page d'erreur personnalisée comme mentionné ici et ici . L'espoir aide quelqu'un.
shaijut
41

J'ai fait fonctionner ma gestion des erreurs en créant un ErrorController qui renvoie les vues de cet article. J'ai également dû ajouter le "Catch All" à l'itinéraire dans global.asax.

Je ne vois pas comment il arrivera à l'une de ces pages d'erreur s'il n'est pas dans le Web.config ..? Mon Web.config devait spécifier:

customErrors mode="On" defaultRedirect="~/Error/Unknown"

et puis j'ai aussi ajouté:

error statusCode="404" redirect="~/Error/NotFound"
Jack Smit
la source
2
Merci - cela m'a aidé, 2 ans plus tard! Que faites-vous si vous ne voulez qu'une erreur personnalisée pour 404, rien d'autre?
Shaul Behr
1
@Shaul une autre année plus tard ... ne définissez pas le defaultRedirect, excluez complètement l'attribut.
NJE
27

La source

NotFoundMVC - Fournit une page 404 conviviale chaque fois qu'un contrôleur, une action ou une route n'est pas trouvé dans votre application ASP.NET MVC3. Une vue appelée NotFound est rendue à la place de la page d'erreur ASP.NET par défaut.

Vous pouvez ajouter ce plugin via nuget en utilisant: Install-Package NotFoundMvc

NotFoundMvc s'installe automatiquement lors du démarrage de l'application Web. Il gère toutes les différentes manières dont une HttpException 404 est généralement levée par ASP.NET MVC. Cela inclut un contrôleur, une action et une route manquants.

Guide d'installation étape par étape:

1 - Faites un clic droit sur votre projet et sélectionnez Gérer les packages Nuget ...

2 - Recherchez NotFoundMvcet installez-le. entrez la description de l'image ici

3 - Une fois l'installation terminée, deux fichiers seront ajoutés à votre projet. Comme le montrent les captures d'écran ci-dessous.

entrez la description de l'image ici

4 - Ouvrez le nouveau NotFound.cshtml présent dans Views / Shared et modifiez-le à votre guise. Maintenant, exécutez l'application et tapez une URL incorrecte, et vous serez accueilli avec une page 404 conviviale.

entrez la description de l'image ici

Pas plus, les utilisateurs recevront un message d'erreur comme Server Error in '/' Application. The resource cannot be found.

J'espère que cela t'aides :)

PS: Félicitations à Andrew Davey pour avoir créé un plugin aussi génial.

Yasser Shaikh
la source
@niico En regardant le code source, il semble définir le code de réponse sur 404, donc oui.
Will Dean
20

Essayez ceci dans web.config pour remplacer les pages d'erreur IIS. C'est la meilleure solution que je suppose, et elle envoie également le code d'état correct.

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" subStatusCode="-1" />
    <remove statusCode="500" subStatusCode="-1" />
    <error statusCode="404" path="Error404.html" responseMode="File" />
    <error statusCode="500" path="Error.html" responseMode="File" />
  </httpErrors>
</system.webServer>

Plus d'informations sur Tipila - Utiliser des pages d'erreur personnalisées ASP.NET MVC

Amila
la source
1
+1. C'est la seule chose qui semblait fonctionner de manière cohérente pour moi sur MVC5 avec plusieurs zones.
hawkke
C'est la solution la plus simple. Cependant, vous ne pouvez pas utiliser la syntaxe de rasoir dans votre page d'erreur.
highace
15

Cette solution n'a pas besoin de modifications de fichier web.config ou de routes fourre-tout.

Tout d'abord, créez un contrôleur comme celui-ci;

public class ErrorController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Title = "Regular Error";
        return View();
    }

    public ActionResult NotFound404()
    {
        ViewBag.Title = "Error 404 - File not Found";
        return View("Index");
    }
}

Créez ensuite la vue sous "Vues / Erreur / Index.cshtml" comme;

 @{
      Layout = "~/Views/Shared/_Layout.cshtml";
  }                     
  <p>We're sorry, page you're looking for is, sadly, not here.</p>

Ajoutez ensuite ce qui suit dans le fichier Global asax comme ci-dessous:

protected void Application_Error(object sender, EventArgs e)
{
        // Do whatever you want to do with the error

        //Show the custom error page...
        Server.ClearError(); 
        var routeData = new RouteData();
        routeData.Values["controller"] = "Error";

        if ((Context.Server.GetLastError() is HttpException) && ((Context.Server.GetLastError() as HttpException).GetHttpCode() != 404))
        {
            routeData.Values["action"] = "Index";
        }
        else
        {
            // Handle 404 error and response code
            Response.StatusCode = 404;
            routeData.Values["action"] = "NotFound404";
        } 
        Response.TrySkipIisCustomErrors = true; // If you are using IIS7, have this line
        IController errorsController = new ErrorController();
        HttpContextWrapper wrapper = new HttpContextWrapper(Context);
        var rc = new System.Web.Routing.RequestContext(wrapper, routeData);
        errorsController.Execute(rc);

        Response.End();
}

Si vous obtenez toujours la page d'erreur IIS personnalisée après cette opération, assurez-vous que les sections suivantes sont commentées (ou vides) dans le fichier de configuration Web:

<system.web>
   <customErrors mode="Off" />
</system.web>
<system.webServer>   
   <httpErrors>     
   </httpErrors>
</system.webServer>
Sujeewa
la source
Je ne pense pas que cette approche fonctionnera dans tous les cas, car un 404 est souvent intercepté par le serveur Web et donc jamais manipulé au niveau de l'application.
Chris Halcrow
Je tiens à ajouter que si vous optez pour cette approche, je recommanderais d'ajouter un Response.End();à la fin de votre gestionnaire Application_Error. Sans cela, seule la première occurrence d'une erreur est déclenchée pour une session donnée, ce qui est un problème lorsque vous avez, par exemple, une journalisation des erreurs personnalisée dans le gestionnaire Application_Error.
Keith
6

Si vous travaillez dans MVC 4, vous pouvez regarder cette solution, cela a fonctionné pour moi.

Ajoutez la méthode Application_Error suivante à my Global.asax:

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    Server.ClearError();

    RouteData routeData = new RouteData();
    routeData.Values.Add("controller", "Error");
    routeData.Values.Add("action", "Index");
    routeData.Values.Add("exception", exception);

    if (exception.GetType() == typeof(HttpException))
    {
        routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
    }
    else
    {
        routeData.Values.Add("statusCode", 500);
    }

    IController controller = new ErrorController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();

Le contrôleur lui-même est vraiment simple:

public class ErrorController : Controller
{
    public ActionResult Index(int statusCode, Exception exception)
    {
        Response.StatusCode = statusCode;
        return View();
    }
}

Vérifiez le code source complet de Mvc4CustomErrorPage sur GitHub .

Duc Hoang
la source
0

J'ai eu le même problème, la chose que vous devez faire est qu'au lieu d'ajouter l'attribut customErrors dans le fichier web.config de votre dossier Views, vous devez l'ajouter dans le fichier web.config dans le dossier racine de vos projets

Fume le
la source
0

Voici la vraie réponse qui permet de personnaliser entièrement la page d'erreur en un seul endroit. Pas besoin de modifier web.config ou de créer un code séparé.

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

Andrus
la source
0

Je vais parler de quelques cas spécifiques,

si vous utilisez la méthode PageNotFound dans HomeController comme ci-dessous

[Route("~/404")]
public ActionResult PageNotFound()
{
  return MyView();
}

cela ne fonctionnerait pas. Mais vous devez effacer les balises Route comme ci-dessous,

//[Route("~/404")]
public ActionResult PageNotFound()
{
  return MyView();
}

Et si vous le changez en tant que méthode Name dans web.config, cela fonctionne. Cependant, n'oubliez pas de faire du code comme ci-dessous dans web.config

<customErrors mode="On">
  <error statusCode="404" redirect="~/PageNotFound" /> 
 *// it is not "~/404" because it is not accepted url in Route Tag like [Route("404")]*
</customErrors>
Furkan ozturk
la source