Question

J'utilise RC2

Utilisation du routage d'URL:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

Ce qui précède semble prendre en charge les requêtes comme celle-ci (en supposant que les tables de routage par défaut soient configurées par le projet MVC initial): & "/ blah / blah / blah / blah &";

Remplacement de HandleUnknownAction () dans le contrôleur lui-même:

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

Cependant, les stratégies précédentes ne gèrent pas une demande adressée à un contrôleur incorrect / inconnu. Par exemple, je n'ai pas de & Quot; / IDoNotExist & Quot ;, si je le demande, je récupère la page générique 404 du serveur Web et non mon 404 si j'utilise le routage + override.

Pour finir, ma question est la suivante: Y at-il un moyen d’attraper ce type de demande en utilisant un itinéraire ou autre chose dans le cadre MVC lui-même?

OU devrais-je simplement utiliser Web.Config customErrors comme gestionnaire 404 et oublier tout cela? Je suppose que si j'utilise customErrors, je devrai stocker la page générique 404 en dehors de / Views en raison des restrictions Web.Config relatives à l'accès direct.

Était-ce utile?

La solution

Le code provient de http://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net -mvc-rc2.aspx et fonctionne également dans ASP.net MVC 1.0

Voici comment je gère les exceptions http:

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

   ILogger logger = Container.Resolve<ILogger>();
   logger.Error(exception);

   Response.Clear();

   HttpException httpException = exception as HttpException;

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

   if (httpException == null)
   {
       routeData.Values.Add("action", "Index");
   }
   else //It's an Http Exception, Let's handle it.
   {
       switch (httpException.GetHttpCode())
       {
          case 404:
              // Page not found.
              routeData.Values.Add("action", "HttpError404");
              break;
          case 500:
              // Server error.
              routeData.Values.Add("action", "HttpError500");
              break;

           // Here you can handle Views to other error codes.
           // I choose a General error template  
           default:
              routeData.Values.Add("action", "General");
              break;
      }
  }           

  // Pass exception details to the target error View.
  routeData.Values.Add("error", exception);

  // Clear the error on server.
  Server.ClearError();

  // Avoid IIS7 getting in the middle
  Response.TrySkipIisCustomErrors = true; 

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData));
}

Autres conseils

Configuration requise pour 404

Mes exigences pour une solution 404 sont décrites ci-dessous. Je montre ci-dessous comment je l’implémente:

  • Je veux gérer les itinéraires correspondants avec de mauvaises actions
  • Je veux gérer les itinéraires correspondants avec de mauvais contrôleurs
  • Je souhaite gérer les itinéraires sans correspondance (adresses URL arbitraires que mon application ne peut pas comprendre). Je ne souhaite pas que ces informations remontent à Global.asax ou à IIS, car Je ne peux pas rediriger correctement vers mon application MVC
  • Je veux un moyen de gérer de la même manière que ci-dessus, les 404 personnalisés - comme lorsqu'un ID est soumis pour un objet qui n'existe pas (peut-être supprimé)
  • Je souhaite que tous mes 404 renvoient une vue MVC (et non une page statique) sur laquelle je peux extraire plus de données ultérieurement si nécessaire ( bons dessins 404 ) et ils doivent renvoyer le code d'état HTTP 404

Solution

Je pense que vous devriez enregistrer Application_Error dans Global.asax pour des raisons plus importantes, telles que les exceptions non gérées et la journalisation (comme La réponse de Shay Jacoby montre) mais pas la manipulation 404. C’est pourquoi ma suggestion garde les éléments 404 dans le fichier Global.asax.

Étape 1: utilisez un emplacement commun pour la logique d’erreurs 404

C’est une bonne idée pour la maintenabilité. Utilisez un ErrorController pour que ces améliorations futures de votre page bien conçue 404 peut s'adapter facilement. De même, assurez-vous que votre réponse contient le code 404 !

.
public class ErrorController : MyController
{
    #region Http404

    public ActionResult Http404(string url)
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        var model = new NotFoundViewModel();
        // If the url is relative ('NotFound' route) then replace with Requested path
        model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
            Request.Url.OriginalString : url;
        // Dont get the user stuck in a 'retry loop' by
        // allowing the Referrer to be the same as the Request
        model.ReferrerUrl = Request.UrlReferrer != null &&
            Request.UrlReferrer.OriginalString != model.RequestedUrl ?
            Request.UrlReferrer.OriginalString : null;

        // TODO: insert ILogger here

        return View("NotFound", model);
    }
    public class NotFoundViewModel
    {
        public string RequestedUrl { get; set; }
        public string ReferrerUrl { get; set; }
    }

    #endregion
}

Étape 2: utilisez une classe de contrôleur de base pour pouvoir appeler facilement votre action 404 personnalisée et câbler HandleUnknownAction

.

404 dans ASP.NET MVC doivent être interceptés à plusieurs endroits. Le premier est InvokeHttp404.

La méthode ErrorController crée un emplacement commun pour le réacheminement vers l'action Http404 et notre nouvelle action url. Pensez DRY !

public abstract class MyController : Controller
{
    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        // If controller is ErrorController dont 'nest' exceptions
        if (this.GetType() != typeof(ErrorController))
            this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

Étape 3: utilisez l’injection de dépendance dans votre Controller Factory et connectez 404 HttpExceptions

Comme ça (il n'est pas nécessaire que ce soit StructureMap):

Exemple MVC1.0:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }
}

Exemple MVC2.0:

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType);
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == 404)
            {
                IController errorController = ObjectFactory.GetInstance<ErrorController>();
                ((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);

                return errorController;
            }
            else
                throw ex;
        }

        return ObjectFactory.GetInstance(controllerType) as Controller;
    }

Je pense qu'il est préférable d'attraper les erreurs plus près de leur origine. C’est pourquoi je préfère ce qui précède au MyController gestionnaire.

C’est le deuxième endroit où prendre 404.

Étape 4: ajoutez un itinéraire NotFound à Global.asax pour les URL qui ne sont pas analysées dans votre application

Cet itinéraire devrait pointer sur notre <=> action. Notez que le <=> paramètre sera une URL relative car le moteur de routage extrait la partie de domaine ici? C’est pourquoi nous avons toute cette logique d’URL conditionnelle à l’étape 1.

        routes.MapRoute("NotFound", "{*url}", 
            new { controller = "Error", action = "Http404" });

C’est le troisième et dernier endroit où attraper des 404 dans une application MVC que vous ne vous invoquez pas. Si vous ne détectez pas d'itinéraires sans correspondance ici, MVC transmettra le problème à ASP.NET (Global.asax) et vous ne le souhaitez pas vraiment dans cette situation.

Étape 5: Enfin, appelez 404 lorsque votre application ne trouve pas quelque chose

Comme lorsqu'un mauvais identifiant est soumis à mon contrôleur de prêts (dérive de <=>):

    //
    // GET: /Detail/ID

    public ActionResult Detail(int ID)
    {
        Loan loan = this._svc.GetLoans().WithID(ID);
        if (loan == null)
            return this.InvokeHttp404(HttpContext);
        else
            return View(loan);
    }

Ce serait bien si tout cela pouvait être branché dans moins d’endroits avec moins de code, mais je pense que cette solution est plus facile à gérer, plus testable et assez pragmatique.

Merci pour les commentaires reçus jusqu'à présent. J'adorerais en avoir plus.

REMARQUE: cette réponse a été modifiée de manière significative par rapport à ma réponse d'origine, mais le but / les exigences sont les mêmes. C'est pourquoi je n'ai pas ajouté de nouvelle réponse

ASP.NET MVC ne prend pas très bien en charge les pages 404 personnalisées. Usine de contrôleur personnalisé, route à tout faire, classe de contrôleur de base avec HandleUnknownAction - argh!

Les pages d'erreur personnalisées IIS sont une meilleure alternative jusqu'à présent:

web.config

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" />
    <error statusCode="404" responseMode="ExecuteURL" path="/Error/PageNotFound" />
  </httpErrors>
</system.webServer>

ErrorController

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View();
    }
}

Exemple de projet

Réponse rapide / TL; DR

entrer la description de l'image ici

Pour les paresseux:

Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0

Ensuite, supprimez cette ligne de global.asax

GlobalFilters.Filters.Add(new HandleErrorAttribute());

Et ceci ne concerne que IIS7 + et IIS Express.

Si vous utilisez Cassini… eh bien… euh… euh… maladroit… awkward

Longue réponse expliquée

Je sais que cela a été répondu. Mais la réponse est VRAIMENT SIMPLE (applaudissements pour David Fowler et Damian Edwards pour avoir vraiment répondu à cette question).

Il n'y a pas besoin de faire quelque chose de personnalisé .

Pour ASP.NET MVC3, tous les morceaux sont là.

Étape 1 - > Mettez à jour votre Web.config en DEUX emplacements.

<system.web>
    <customErrors mode="On" defaultRedirect="/ServerError">
      <error statusCode="404" redirect="/NotFound" />
    </customErrors>

et

<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" path="/NotFound" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" path="/ServerError" responseMode="ExecuteURL" />
    </httpErrors>    

...
<system.webServer>
...
</system.web>

Maintenant, prenez bien note des ITINÉRAIRES que j'ai décidé d'utiliser. Vous pouvez utiliser n'importe quoi, mais mes itinéraires sont

  • /NotFound < - pour une page d'erreur 404 non trouvée.
  • /ServerError < - pour toute autre erreur, incluez les erreurs qui se produisent dans mon code. il s'agit d'une erreur de 500 serveur interne

Vous voyez comment la première section de <system.web> ne contient que une entrée personnalisée? L'entrée statusCode="404"? Je n'ai répertorié qu'un seul code d'état car toutes les autres erreurs, y compris 500 Server Error (c'est-à-dire l'erreur embêtante qui se produit lorsque votre code contient un bogue et bloque la demande de l'utilisateur). Toutes les autres erreurs sont gérées par le paramètre < => .. qui dit, si vous n'êtes pas une page 404 non trouvée, alors veuillez vous rendre sur la route defaultRedirect="/ServerError".

Ok. c'est à l'écart .. maintenant à mes routes énumérées dans axd's

Étape 2 - Création des itinéraires dans Global.asax

Voici ma section de route complète ..

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});

    routes.MapRoute(
        "Error - 404",
        "NotFound",
        new { controller = "Error", action = "NotFound" }
        );

    routes.MapRoute(
        "Error - 500",
        "ServerError",
        new { controller = "Error", action = "ServerError"}
        );

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new {controller = "Home", action = "Index", id = UrlParameter.Optional}
        );
}

Cela répertorie deux routes ignorées - > favicons et [HandleError] (ooo! bonus ignore route, pour vous!) Ensuite (et la commande est IMPERATIVE ICI), j'ai mes deux routes de traitement d'erreur explicites .. suivies par d'autres routes. Dans ce cas, celui par défaut. Bien sûr, j'en ai plus, mais c'est spécial pour mon site web. Assurez-vous simplement que les itinéraires d'erreur sont en haut de la liste. L'ordre est impératif .

Enfin, même si nous sommes dans notre fichier ASP.NET, nous n'enregistrons pas globalement l'attribut HandleError. Non, non, non monsieur. Nadda. Nan. Nien. Négatif. Noooooooooo ...

Supprimer cette ligne de Server.GetLastError()

public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    public ActionResult ServerError()
    {
        Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        // Todo: Pass the exception into the view model, which you can make.
        //       That's an exercise, dear reader, for -you-.
        //       In case u want to pass it to the view, if you're admin, etc.
        // if (User.IsAdmin) // <-- I just made that up :) U get the idea...
        // {
        //     var exception = Server.GetLastError();
        //     // etc..
        // }

        return View();
    }

    // Shhh .. secret test method .. ooOOooOooOOOooohhhhhhhh
    public ActionResult ThrowError()
    {
        throw new NotImplementedException("Pew ^ Pew");
    }
}

Étape 3 - Créez le contrôleur avec les méthodes d'action

Maintenant .. nous ajoutons un contrôleur avec deux méthodes d'action ...

<*>

Ok, vérifions cela. Tout d’abord, il y a NON Application_Error(object sender, EventArgs e) attribut ici. Pourquoi? Parce que le framework <=> intégré gère déjà les erreurs ET nous avons spécifié toute la merde que nous devons faire pour gérer une erreur :) C'est dans cette méthode!

Ensuite, j'ai les deux méthodes d'action. Rien de difficile là-bas. Si vous souhaitez afficher des informations sur les exceptions, vous pouvez utiliser <=> pour obtenir ces informations.

Bonus WTF: Oui, j'ai créé une troisième méthode d'action pour tester la gestion des erreurs.

Étape 4: créez les vues

.

Et enfin, créez deux vues. Mettez-les à la vue normale pour ce contrôleur.

entrer la description de l'image ici

Commentaires sur les bonus

  • Vous n'avez pas besoin d'un <=>
  • Toutes les étapes ci-dessus fonctionnent à 100% avec Elmah . Elmah fraking wroxs!

Et ça, mes amis, ça devrait être ça.

Maintenant, félicitations pour avoir autant lu et méritez une Licorne!

entrer la description de l'image ici

J'ai étudié BEAUCOUP pour gérer correctement les 404 dans MVC (plus précisément MVC3) , et ceci, IMHO est la meilleure solution que j'ai proposé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));
        }
    }
}

ErrorsController:

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;
    }
}

(Facultatif)

Explication:

D'après ce que je sais, une application ASP.NET MVC3 peut générer 404 cas différents.

(Généré automatiquement par ASP.NET Framework:)

(1) Une URL ne trouve pas de correspondance dans le tableau de routage.

(Généré automatiquement par ASP.NET MVC Framework:)

(2) Une URL trouve une correspondance dans la table de routage, mais spécifie un contrôleur inexistant.

(3) Une URL trouve une correspondance dans la table de routage, mais spécifie une action inexistante.

(généré manuellement:)

(4) Une action renvoie un HttpNotFoundResult en utilisant la méthode HttpNotFound ().

(5) Une action lève une exception HttpException avec le code d'état 404.

(6) Une action modifie manuellement la propriété Response.StatusCode sur 404.

Normalement, vous souhaitez atteindre 3 objectifs:

(1) afficher une page d'erreur 404 personnalisée à l'utilisateur.

(2) Conservez le code d'état 404 sur la réponse du client (particulièrement important pour le référencement).

(3) envoyez la réponse directement, sans impliquer de redirection 302.

Il existe différentes méthodes pour y parvenir:

(1)

<system.web>
    <customErrors mode="On">
        <error statusCode="404" redirect="~/Errors/NotFound"/>
    </customError>
</system.web>

Problèmes avec cette solution:

  1. Ne correspond pas à l'objectif (1) dans les cas (1), (4), (6).
  2. Ne se conforme pas automatiquement à l'objectif (2). Il doit être programmé manuellement.
  3. Ne correspond pas à l'objectif (3).

(2)

<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:

  1. Ne fonctionne que sur IIS 7 +.
  2. Ne répond pas à l'objectif (1) dans les cas (2), (3), (5).
  3. Ne se conforme pas automatiquement à l'objectif (2). Il doit être programmé manuellement.

(3)

<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:

  1. Ne fonctionne que sur IIS 7 +.
  2. Ne se conforme pas automatiquement à l'objectif (2). Il doit être programmé manuellement.
  3. Il masque les exceptions http au niveau de l'application. Par exemple. ne peut pas utiliser la section customErrors, System.Web.Mvc.HandleErrorAttribute, etc. Elle ne peut pas uniquement afficher les pages d'erreur génériques.

(4)

<*>

et

<*>

Problèmes avec cette solution:

  1. Ne fonctionne que sur IIS 7 +.
  2. Ne se conforme pas automatiquement à l'objectif (2). Il doit être programmé manuellement.
  3. Ne correspond pas à l'objectif (3) dans les cas (2), (3), (5).

Les personnes qui en avaient déjà souffert auparavant ont même essayé de créer leurs propres bibliothèques (voir http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html ). Mais la solution précédente semble couvrir tous les cas sans la complexité liée à l’utilisation d’une bibliothèque externe.

J'aime beaucoup la solution de cottsaks et pense qu’elle est très clairement expliquée. mon seul ajout était de modifier l'étape 2 comme suit

public abstract class MyController : Controller
{

    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        //if controller is ErrorController dont 'nest' exceptions
        if(this.GetType() != typeof(ErrorController))
        this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

En gros, cela empêche les URL contenant des actions non valides ET les contrôleurs de déclencher deux fois le programme d'exception. par exemple pour des URL telles que asdfsdf / dfgdfgd

La seule façon pour moi de faire en sorte que la méthode de @ cottsak fonctionne avec des contrôleurs non valides consistait à modifier la demande de route existante dans CustomControllerFactory, comme suit:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                return base.GetControllerInstance(requestContext, controllerType); 
            else
                return ObjectFactory.GetInstance(controllerType) as Controller;
        }
        catch (HttpException ex)
        {
            if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
            {
                requestContext.RouteData.Values["controller"] = "Error";
                requestContext.RouteData.Values["action"] = "Http404";
                requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);

                return ObjectFactory.GetInstance<ErrorController>();
            }
            else
                throw ex;
        }
    }
}

Je dois mentionner que j'utilise MVC 2.0.

Voici une autre méthode utilisant les outils MVC qui vous permet de gérer les demandes adressées à des noms de contrôleur, des noms de route incorrects et à tout autre critère que vous voyez s’intégrer à une méthode Action. Personnellement, je préfère éviter autant de paramètres web.config que possible, car ils effectuent la redirection 302/200 et ne prennent pas en charge ResponseRewrite (Server.Transfer) à l'aide de vues Razor. Je préférerais renvoyer un 404 avec une page d'erreur personnalisée pour des raisons de référencement.

Ceci est en partie une nouvelle interprétation de la technique de Cottsak ci-dessus.

Cette solution utilise également des paramètres Web.config minimaux, privilégiant les filtres d'erreur MVC 3.

Utilisation

Lancez simplement une exception HttpException d'une action ou d'un ActionFilterAttribute personnalisé.

Throw New HttpException(HttpStatusCode.NotFound, "[Custom Exception Message Here]")

Étape 1

Ajoutez le paramètre suivant à votre web.config. Ceci est nécessaire pour utiliser le HandleErrorAttribute de MVC.

<customErrors mode="On" redirectMode="ResponseRedirect" />

Étape 2

Ajoutez un HandleHttpErrorAttribute personnalisé similaire au HandleErrorAttribute du framework MVC, à l'exception des erreurs HTTP:

<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Public Class HandleHttpErrorAttribute
    Inherits FilterAttribute
    Implements IExceptionFilter

    Private Const m_DefaultViewFormat As String = "ErrorHttp{0}"

    Private m_HttpCode As HttpStatusCode
    Private m_Master As String
    Private m_View As String

    Public Property HttpCode As HttpStatusCode
        Get
            If m_HttpCode = 0 Then
                Return HttpStatusCode.NotFound
            End If
            Return m_HttpCode
        End Get
        Set(value As HttpStatusCode)
            m_HttpCode = value
        End Set
    End Property

    Public Property Master As String
        Get
            Return If(m_Master, String.Empty)
        End Get
        Set(value As String)
            m_Master = value
        End Set
    End Property

    Public Property View As String
        Get
            If String.IsNullOrEmpty(m_View) Then
                Return String.Format(m_DefaultViewFormat, Me.HttpCode)
            End If
            Return m_View
        End Get
        Set(value As String)
            m_View = value
        End Set
    End Property

    Public Sub OnException(filterContext As System.Web.Mvc.ExceptionContext) Implements System.Web.Mvc.IExceptionFilter.OnException
        If filterContext Is Nothing Then Throw New ArgumentException("filterContext")

        If filterContext.IsChildAction Then
            Return
        End If

        If filterContext.ExceptionHandled OrElse Not filterContext.HttpContext.IsCustomErrorEnabled Then
            Return
        End If

        Dim ex As HttpException = TryCast(filterContext.Exception, HttpException)
        If ex Is Nothing OrElse ex.GetHttpCode = HttpStatusCode.InternalServerError Then
            Return
        End If

        If ex.GetHttpCode <> Me.HttpCode Then
            Return
        End If

        Dim controllerName As String = filterContext.RouteData.Values("controller")
        Dim actionName As String = filterContext.RouteData.Values("action")
        Dim model As New HandleErrorInfo(filterContext.Exception, controllerName, actionName)

        filterContext.Result = New ViewResult With {
            .ViewName = Me.View,
            .MasterName = Me.Master,
            .ViewData = New ViewDataDictionary(Of HandleErrorInfo)(model),
            .TempData = filterContext.Controller.TempData
        }
        filterContext.ExceptionHandled = True
        filterContext.HttpContext.Response.Clear()
        filterContext.HttpContext.Response.StatusCode = Me.HttpCode
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
    End Sub
End Class

Étape 3

Ajouter des filtres à GlobalFilterCollection (GlobalFilters.Filters) dans Global.asax. Cet exemple acheminera toutes les erreurs InternalServerError (500) vers la vue Erreur partagée (Views/Shared/Error.vbhtml). Les erreurs NotFound (404) seront également envoyées à ErrorHttp404.vbhtml dans les vues partagées. J'ai ajouté une erreur 401 ici pour vous montrer comment cela peut être étendu pour des codes d'erreur HTTP supplémentaires. Notez que ces vues doivent être partagées et qu'elles utilisent toutes l'objet System.Web.Mvc.HandleErrorInfo en tant que modèle.

filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp401", .HttpCode = HttpStatusCode.Unauthorized})
filters.Add(New HandleHttpErrorAttribute With {.View = "ErrorHttp404", .HttpCode = HttpStatusCode.NotFound})
filters.Add(New HandleErrorAttribute With {.View = "Error"})

Étape 4

Créez une classe de contrôleur de base et en héritez dans vos contrôleurs. Cette étape nous permet de gérer les noms d’action inconnus et de générer l’erreur HTTP 404 dans notre HandleHttpErrorAttribute.

Public Class BaseController
    Inherits System.Web.Mvc.Controller

    Protected Overrides Sub HandleUnknownAction(actionName As String)
        Me.ActionInvoker.InvokeAction(Me.ControllerContext, "Unknown")
    End Sub

    Public Function Unknown() As ActionResult
        Throw New HttpException(HttpStatusCode.NotFound, "The specified controller or action does not exist.")
        Return New EmptyResult
    End Function
End Class

Étape 5

Créez un remplacement ControllerFactory et remplacez-le dans votre fichier Global.asax dans Application_Start. Cette étape nous permet de déclencher l'exception HTTP 404 lorsqu'un nom de contrôleur non valide a été spécifié.

Public Class MyControllerFactory
    Inherits DefaultControllerFactory

    Protected Overrides Function GetControllerInstance(requestContext As System.Web.Routing.RequestContext, controllerType As System.Type) As System.Web.Mvc.IController
        Try
            Return MyBase.GetControllerInstance(requestContext, controllerType)
        Catch ex As HttpException
            Return DependencyResolver.Current.GetService(Of BaseController)()
        End Try
    End Function
End Class

'In Global.asax.vb Application_Start:

controllerBuilder.Current.SetControllerFactory(New MyControllerFactory)

étape 6

Incluez un itinéraire spécial dans votre RoutTable.Routes pour l'action BaseController Unknown. Cela nous aidera à lever un 404 dans le cas où un utilisateur accède à un contrôleur inconnu ou à une action inconnue.

'BaseController
routes.MapRoute( _
    "Unknown", "BaseController/{action}/{id}", _
    New With {.controller = "BaseController", .action = "Unknown", .id = UrlParameter.Optional} _
)

Résumé

Cet exemple montre comment utiliser la structure MVC pour renvoyer 404 codes d'erreur HTTP au navigateur, sans redirection, à l'aide d'attributs de filtre et de vues d'erreur partagées. Il montre également l’affichage de la même page d’erreur personnalisée lorsque des noms de contrôleur et d’action non valides sont spécifiés.

Je vais ajouter une capture d'écran d'un nom de contrôleur non valide, d'un nom d'action et d'un 404 personnalisé généré à partir de l'action Home / TriggerNotFound si j'obtiens suffisamment de votes pour en publier un =). Fiddler renvoie un message 404 lorsque j'accède aux URL suivantes à l'aide de cette solution:

/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound
Le commentaire ci-dessus de

cottsak et ces articles étaient de bonnes références.

Ma solution raccourcie fonctionnant avec des zones, des contrôleurs et des actions non gérés:

  1. Créer une vue 404.cshtml.

  2. Créez une classe de base pour vos contrôleurs:

    public class Controller : System.Web.Mvc.Controller
    {
        protected override void HandleUnknownAction(string actionName)
        {
            Http404().ExecuteResult(ControllerContext);
        }
    
        protected virtual ViewResult Http404()
        {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return View("404");
        }
    }
    
  3. Créez une usine de contrôleur personnalisée renvoyant votre contrôleur de base en tant que solution de secours:

    public class ControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            if (controllerType != null)
                return base.GetControllerInstance(requestContext, controllerType);
    
            return new Controller();
        }
    }
    
  4. Ajoutez à Application_Start() la ligne suivante:

    ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
    

Dans MVC4 WebAPI 404 peut être géré de la manière suivante,

APICONTROLLER COURS

    // GET /api/courses/5
    public HttpResponseMessage<Courses> Get(int id)
    {
        HttpResponseMessage<Courses> resp = null;

        var aCourse = _courses.Where(c => c.Id == id).FirstOrDefault();

        resp = aCourse == null ? new HttpResponseMessage<Courses>(System.Net.HttpStatusCode.NotFound) : new HttpResponseMessage<Courses>(aCourse);

        return resp;
    }

HOME CONTROLLER

public ActionResult Course(int id)
{
    return View(id);
}

VIEW

<div id="course"></div>
<script type="text/javascript">
    var id = @Model;
    var course = $('#course');
    $.ajax({    
        url: '/api/courses/' + id,
        success: function (data) {
            course.text(data.Name);
        },
        statusCode: {
            404: function() 
            {
                course.text('Course not available!');    
            }
        }
    });
</script>

GLOBAL

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

RÉSULTATS

entrer la description de l'image ici

Essayez de ne pas trouver MVC dans le nuget. Cela fonctionne, pas de configuration.

Ma solution, au cas où quelqu'un la jugerait utile.

Dans Web.config:

<system.web>
    <customErrors mode="On" defaultRedirect="Error" >
      <error statusCode="404" redirect="~/Error/PageNotFound"/>
    </customErrors>
    ...
</system.web>

Dans Controllers/ErrorController.cs:

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        if(Request.IsAjaxRequest()) {
            Response.StatusCode = (int)HttpStatusCode.NotFound;
            return Content("Not Found", "text/plain");
        }

        return View();
    }
}

Ajoutez un PageNotFound.cshtml dans le Shared dossier et le tour est joué.

Il me semble que la CustomErrors configuration standard ne devrait fonctionner que . Cependant, en raison de la confiance accordée à Server.Transfer, il semble que la mise en œuvre interne de ResponseRewrite ne soit pas compatible avec MVC. .

Cela me semble être un trou de fonctionnalité criant. J'ai donc décidé de réimplémenter cette fonctionnalité à l'aide d'un module HTTP. La solution ci-dessous vous permet de gérer n’importe quel code de statut HTTP (y compris le code 404) en le redirigeant vers n’importe quel itinéraire MVC valide, comme vous le feriez normalement.

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
    <error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>

Ceci a été testé sur les plates-formes suivantes;

  • MVC4 en mode pipeline intégré (IIS Express 8)
  • MVC4 en mode classique (VS Development Server, Cassini)
  • MVC4 en mode classique (IIS6)

Avantages

  • Solution générique pouvant être insérée dans n'importe quel projet MVC
  • Active la prise en charge de la configuration des erreurs personnalisées traditionnelles
  • Fonctionne à la fois dans les modes Pipeline intégré et Classique

La solution

namespace Foo.Bar.Modules {

    /// <summary>
    /// Enables support for CustomErrors ResponseRewrite mode in MVC.
    /// </summary>
    public class ErrorHandler : IHttpModule {

        private HttpContext HttpContext { get { return HttpContext.Current; } }
        private CustomErrorsSection CustomErrors { get; set; }

        public void Init(HttpApplication application) {
            System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
            CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");

            application.EndRequest += Application_EndRequest;
        }

        protected void Application_EndRequest(object sender, EventArgs e) {

            // only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it)
            if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {

                int statusCode = HttpContext.Response.StatusCode;

                // if this request has thrown an exception then find the real status code
                Exception exception = HttpContext.Error;
                if (exception != null) {
                    // set default error status code for application exceptions
                    statusCode = (int)HttpStatusCode.InternalServerError;
                }

                HttpException httpException = exception as HttpException;
                if (httpException != null) {
                    statusCode = httpException.GetHttpCode();
                }

                if ((HttpStatusCode)statusCode != HttpStatusCode.OK) {

                    Dictionary<int, string> errorPaths = new Dictionary<int, string>();

                    foreach (CustomError error in CustomErrors.Errors) {
                        errorPaths.Add(error.StatusCode, error.Redirect);
                    }

                    // find a custom error path for this status code
                    if (errorPaths.Keys.Contains(statusCode)) {
                        string url = errorPaths[statusCode];

                        // avoid circular redirects
                        if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {

                            HttpContext.Response.Clear();
                            HttpContext.Response.TrySkipIisCustomErrors = true;

                            HttpContext.Server.ClearError();

                            // do the redirect here
                            if (HttpRuntime.UsingIntegratedPipeline) {
                                HttpContext.Server.TransferRequest(url, true);
                            }
                            else {
                                HttpContext.RewritePath(url, false);

                                IHttpHandler httpHandler = new MvcHttpHandler();
                                httpHandler.ProcessRequest(HttpContext);
                            }

                            // return the original status code to the client
                            // (this won't work in integrated pipleline mode)
                            HttpContext.Response.StatusCode = statusCode;

                        }
                    }

                }

            }

        }

        public void Dispose() {

        }


    }

}

Utilisation

Incluez ceci en tant que module HTTP final dans votre web.config

  <system.web>
    <httpModules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </httpModules>
  </system.web>

  <!-- IIS7+ -->
  <system.webServer>
    <modules>
      <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
    </modules>
  </system.webServer>

Pour ceux qui y prêtent attention, vous remarquerez qu'en mode Pipeline intégré, cela répondra toujours avec HTTP 200 en raison du fonctionnement de Server.TransferRequest. Pour retourner le code d'erreur approprié, j'utilise le contrôleur d'erreur suivant.

public class ErrorController : Controller {

    public ErrorController() { }

    public ActionResult Index(int id) {
        // pass real error code to client
        HttpContext.Response.StatusCode = id;
        HttpContext.Response.TrySkipIisCustomErrors = true;

        return View("Errors/" + id.ToString());
    }

}

La gestion des erreurs dans ASP.NET MVC n’est qu’un problème. J'ai essayé beaucoup de suggestions sur cette page et sur d'autres questions et sites et rien ne marche bien. Une suggestion a été de gérer les erreurs sur web.config à l'intérieur de system.webserver mais que uniquement renvoie des pages vierges .

Mon objectif en proposant cette solution était de

  • PAS REDIRECT
  • Renvoyez les CODES D'ÉTAT APPROPRIÉS pas 200 / Ok comme le traitement d'erreur par défaut

Voici ma solution.

1 . Ajoutez les éléments suivants à la section system.web

   <system.web>
     <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404"  redirect="~/Error/404.aspx" />
      <error statusCode="500" redirect="~/Error/500.aspx" />
     </customErrors>
    <system.web>

Ce qui précède gère les URL non gérées par routes.config et les exceptions non gérées, en particulier celles rencontrées dans les vues. Remarquez que j'ai utilisé aspx et non html . C’est pour que je puisse ajouter un code de réponse sur le code situé derrière.

2 . Créez un dossier appelé Erreur (ou ce que vous préférez) à la racine de votre projet et ajoutez les deux formulaires Web. Ci-dessous ma page 404;

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="404.aspx.cs" Inherits="Myapp.Error._404" %>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title >Page Not found</title>
    <link href="<%=ResolveUrl("~/Content/myapp.css")%>" rel="stylesheet" />
</head>
<body>
    <div class="top-nav">
      <a runat="server" class="company-logo" href="~/"></a>
    </div>
    <div>
        <h1>404 - Page Not found</h1>
        <p>The page you are looking for cannot be found.</p>
        <hr />
        <footer></footer>
    </div>
</body>
</html>

Et sur le code derrière je règle le code de réponse

protected void Page_Load(object sender, EventArgs e)
{
    Response.StatusCode = 404;
}

Faites la même chose pour la page 500

3 .Pour gérer les erreurs au sein des contrôleurs. Il y a plusieurs façons de le faire. C'est ce qui a fonctionné pour moi. Tous mes contrôleurs héritent d'un contrôleur de base. Dans le contrôleur de base, j'ai les méthodes suivantes

protected ActionResult ShowNotFound()
{
    return ShowNotFound("Page not found....");
}

protected ActionResult ShowNotFound(string message)
{
    return ShowCustomError(HttpStatusCode.NotFound, message);
}

protected ActionResult ShowServerError()
{
    return ShowServerError("Application error....");
}

protected ActionResult ShowServerError(string message)
{
    return ShowCustomError(HttpStatusCode.InternalServerError, message);
}

protected ActionResult ShowNotAuthorized()
{
    return ShowNotAuthorized("You are not allowed ....");

}

protected ActionResult ShowNotAuthorized(string message)
{
    return ShowCustomError(HttpStatusCode.Forbidden, message);
}

protected ActionResult ShowCustomError(HttpStatusCode statusCode, string message)
{
    Response.StatusCode = (int)statusCode;
    string title = "";
    switch (statusCode)
    {
        case HttpStatusCode.NotFound:
            title = "404 - Not found";
            break;
        case HttpStatusCode.Forbidden:
            title = "403 - Access Denied";
            break;
        default:
            title = "500 - Application Error";
            break;
    }
    ViewBag.Title = title;
    ViewBag.Message = message;
    return View("CustomError");
}

4 . Ajoutez le fichier CustomError.cshtml à votre dossier de vues Partagées . Ci-dessous est le mien;

<h1>@ViewBag.Title</h1>
<br />
<p>@ViewBag.Message</p>

Maintenant, dans votre contrôleur d’application, vous pouvez faire quelque chose comme ceci;

public class WidgetsController : ControllerBase
{
  [HttpGet]
  public ActionResult Edit(int id)
  {
    Try
    {
       var widget = db.getWidgetById(id);
       if(widget == null)
          return ShowNotFound();
          //or return ShowNotFound("Invalid widget!");
       return View(widget);
    }
    catch(Exception ex)
    {
       //log error
       logger.Error(ex)
       return ShowServerError();
    }
  }
}

Passons maintenant à la mise en garde . Il ne gérera pas les erreurs de fichiers statiques. Ainsi, si vous avez un itinéraire tel que exemple.com/widgets et que l'utilisateur le modifie en exemple.com/widgets.html , ils obtiendront la page d'erreur par défaut d'IIS afin vous devez gérer les erreurs de niveau IIS d'une autre manière.

Publier une réponse car mon commentaire était trop long ...

C’est à la fois un commentaire et des questions sur le message / réponse de la licorne:

https://stackoverflow.com/a/7499406/687549

Je préfère cette réponse aux autres en raison de sa simplicité et du fait qu'apparemment, certaines personnes de Microsoft ont été consultées. Cependant, j’ai eu trois questions et si on peut y répondre, j’appellerai cette réponse le Saint-Graal de toutes les réponses d’erreur 404/500 sur les interwebs d’une application ASP.NET MVC (x).

@ Pure.Krome

  1. Pouvez-vous mettre à jour votre réponse avec les éléments de référencement des commentaires mentionnés par GWB (il n’a jamais été question de cela dans votre réponse) - <customErrors mode="On" redirectMode="ResponseRewrite"> et <httpErrors errorMode="Custom" existingResponse="Replace">?

  2. Pouvez-vous demander à vos amis de l’équipe ASP.NET s’il est acceptable de le faire comme cela - ce serait bien d’avoir une confirmation - c’est peut-être un gros non-non de changer redirectMode et existingResponse dans de cette façon pour pouvoir jouer bien avec le référencement?!

  3. Pouvez-vous ajouter des précisions sur tous ces éléments (customErrors redirectMode="ResponseRewrite", customErrors redirectMode="ResponseRedirect", httpErrors errorMode="Custom" existingResponse="Replace", SUPPRIMER customErrors COMPLÈTEMENT comme l'a suggéré quelqu'un) après avoir parlé à vos amis chez Microsoft?

Comme je le disais; ce serait un surcroît si nous pouvions compléter votre réponse car cela semble être une question assez populaire avec plus de 54 000 vues.

Mettre à jour : la réponse de la Licorne effectue un résultat 302 trouvé et un résultat correct 200 et ne peut pas être modifiée pour ne renvoyer que 404 via un itinéraire. Ce doit être un fichier physique qui n'est pas très MVC: ish. Passons donc à une autre solution. Dommage car cela semblait être le MVC ultime: répondez-y si loin.

Ajout de ma solution, qui est presque identique à celle d'Herman Kan, avec une petite ride pour lui permettre de fonctionner pour mon projet.

Créez un contrôleur d'erreur personnalisé:

public class Error404Controller : BaseController
{
    [HttpGet]
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View("404");
    }
}

Créez ensuite une fabrique de contrôleurs personnalisés:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return controllerType == null ? new Error404Controller() : base.GetControllerInstance(requestContext, controllerType);
    }
}

Enfin, ajoutez un remplacement au contrôleur d'erreur personnalisé:

protected override void HandleUnknownAction(string actionName)
{
    var errorRoute = new RouteData();
    errorRoute.Values.Add("controller", "Error404");
    errorRoute.Values.Add("action", "PageNotFound");
    new Error404Controller().Execute(new RequestContext(HttpContext, errorRoute));
}

Et c'est tout. Pas besoin de modifications de Web.config.

1) Créez une classe de contrôleur abstraite.

public abstract class MyController:Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View("NotFound");
    }

    protected override void HandleUnknownAction(string actionName)
    {
        this.ActionInvoker.InvokeAction(this.ControllerContext, "NotFound");
    }
    protected override void OnAuthorization(AuthorizationContext filterContext) { }
}  

2) Créez l'héritage de cette classe abstraite dans tous vos contrôleurs

public class HomeController : MyController
{}  

3) Et ajoutez une vue nommée " NotFound " dans votre dossier View-Shared.

J'ai parcouru la plupart des solutions publiées sur ce fil. Même si cette question est peut-être ancienne, elle est toujours très applicable aux nouveaux projets, aussi, j’ai passé beaucoup de temps à lire les réponses présentées ici ainsi que ailleurs.

Comme @Marco a souligné les différents cas dans lesquels une 404 peut se produire, j'ai vérifié la solution que j'ai compilée ensemble sur cette liste. En plus de sa liste d'exigences, j'ai également ajouté une autre.

  • La solution doit pouvoir gérer les appels MVC et AJAX / WebAPI de la manière la plus appropriée. (Par exemple, si 404 se produit dans MVC, la page Introuvable doit s'afficher et si 404 se présente dans WebAPI, il ne devrait pas détourner la réponse XML / JSON afin que le Javascript qui consomme puisse l'analyser facilement).

Cette solution est multipliée par 2:

La première partie provient de @Guillaume à l'adresse https://stackoverflow.com/a/27354140/2310818 . Leur solution prend en charge tous les 404 causés par une route, un contrôleur et une action non valides.

L’idée est de créer un formulaire Web, puis de le faire appeler l’action NotFound de votre contrôleur d’erreurs MVC. Tout cela sans aucune redirection, vous ne verrez donc pas un seul 302 dans Fiddler. L'URL d'origine est également préservée, ce qui rend cette solution fantastique!

La deuxième partie provient de @Germ & # 225; n à l'adresse https://stackoverflow.com/a/5536676 / 2310818 . Leur solution prend en charge tous les 404 retournés par vos actions sous la forme de HttpNotFoundResult () ou jette une nouvelle HttpException ()!

L'idée est de faire en sorte qu'un filtre examine la réponse ainsi que l'exception émise par vos contrôleurs MVC et appelle l'action appropriée dans votre contrôleur d'erreurs. Encore une fois, cette solution fonctionne sans aucune redirection et l'URL d'origine est conservée!

Comme vous pouvez le constater, ces deux solutions combinées offrent un mécanisme de traitement des erreurs très robuste et répondent à toutes les exigences répertoriées par @Marco, ainsi qu'à mes exigences. Si vous souhaitez voir un échantillon de travail ou une démonstration de cette solution, laissez-la dans les commentaires et je me ferai un plaisir de la mettre ensemble.

J'ai parcouru tous les articles mais rien ne fonctionne pour moi: Mon exigence utilisateur doit taper tout ce qui se trouve dans votre page 404 personnalisée dans l'URL devrait apparaître.J'ai pensé que c'était très simple.

 <system.web>
    <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/PageNotFound.aspx"/>
    </customErrors>
  </system.web>
<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

J'ai trouvé cet article très utile.Vous devriez le lire immédiatement. Page d'erreur Custome -Ben Foster

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top