web-dev-qa-db-fra.com

CustomErrors ne fonctionne pas lors de la définition de redirectMode = "ResponseRewrite"

Dans un ancien site, je modifiais le fonctionnement de CustomErrors en ajoutant redirectMode="ResponseRewrite" (nouveau dans 3.5 SP1):

<customErrors mode="RemoteOnly" defaultRedirect="Error.aspx" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="404.aspx" />
</customErrors> 

La chose est: il me montre la page d'erreur générique (celle que vous obtenez lorsque vous ne définissez pas customErrors. Si je supprime leredirectMode="ResponseRewrite" partie, ça marche bien.

Je suis sûr que 3.5 SP1 est installé sur le serveur, car j'utilise le même paramètre sur d'autres sites hébergés sur le même serveur.

Des idées?

71
Eduardo Molteni

J'ai trouvé que le problème était dans Error.aspx. Vous ne trouvez toujours pas l'erreur réelle dans error.aspx à l'origine du problème.

La modification de la page en un fichier html statique a résolu le problème.

1
Eduardo Molteni

Il est important de noter pour quiconque essaie de le faire dans une application MVC que ResponseRewrite utilise Server.Transfer Dans les coulisses. Par conséquent, le defaultRedirect doit correspondre à un fichier légitime sur le système de fichiers. Apparemment, Server.Transfer n'est pas compatible avec les routes MVC, par conséquent, si votre page d'erreur est servie par une action de contrôleur, Server.Transfer va chercher/Erreur/Peu importe, ne pas le trouver sur le système de fichiers et retourner une page d'erreur 404 générique!

100
Michael Hallock

La seule façon qui a parfaitement fonctionné pour moi est de désactiver les erreurs personnalisées et de remplacer les pages d'erreur d'iis via web.config. Il envoie le code d'état correct avec la réponse et a l'avantage de ne pas passer par le mvc.

voici le code

  1. Désactiver les erreurs personnalisées

    <customErrors mode="Off" />
    
  2. Remplacer les pages d'erreur

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

Remarque. Utilisation responsemode="file" si l'url est un lien direct vers un fichier

info: http://tipila.com/tips/use-custom-error-pages-aspnet-mvc

48
Amila

Ce qui se passe est IIS voit le code d'état d'erreur et présente sa propre page d'erreur au lieu de la vôtre. Pour résoudre ce problème, vous devez le définir dans le code situé derrière la page de votre page d'erreur pour éviter IIS en procédant ainsi:

Response.TrySkipIisCustomErrors = true;

Cela ne fonctionnera que dans IIS7 ou supérieur, pour les versions antérieures de IIS, vous devrez jouer avec les paramètres de la page d'erreur.

20
Michael

En raison de la dépendance envers Server.Transfer il semble que l'implémentation interne de ResponseRewrite ne soit pas compatible avec MVC.

Cela me semble être un trou de fonctionnalité flagrant, j'ai donc décidé de réimplémenter cette fonctionnalité à l'aide d'un module HTTP, de sorte que cela fonctionne juste. La solution ci-dessous vous permet de gérer les erreurs en redirigeant vers n'importe quelle route MVC valide (y compris les fichiers physiques) comme vous le feriez normalement.

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

Cela 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)

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() {

        }


    }

}

tilisation

Incluez-le comme 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>
14
Red Taz

Je sais que cette question est un peu ancienne, mais j'ai pensé que je devrais souligner qu'il n'a pas besoin d'être un fichier statique pour que cela fonctionne.

Je suis tombé sur une chose similaire, et il s'agit simplement de trouver cette erreur dans votre Error.aspx, dans notre cas, c'est parce que la page maître utilisée reposait sur un morceau de données de session et lorsque ResponseRewrite a été défini, la session n'est pas disponible pour notre page Error.aspx.

Je n'ai pas encore déterminé si cette indisponibilité de session est due à notre configuration d'application spécifique ou à une partie "par conception" d'ASP.net.

9
Chris

J'ai créé une page d'erreur dans aspx qui transfère la requête vers un contrôleur ASP.NET MVC. Vous pouvez réécrire la requête sur cette page aspx et elle transférera la requête sur votre contrôleur personnalisé.

protected void Page_Load(object sender, EventArgs e)
{
  //Get status code
  var queryStatusCode = Request.QueryString.Get("code");
  int statusCode;
  if (!int.TryParse(queryStatusCode, out statusCode))
  {
    var lastError = Server.GetLastError();
    HttpException ex = lastError as HttpException;
    statusCode = ex == null ? 500 : ex.GetHttpCode();
  }
  Response.StatusCode = statusCode;

  // Execute a route
  RouteData routeData = new RouteData();
  string controllerName = Request.QueryString.Get("controller") ?? "Errors";
  routeData.Values.Add("controller", controllerName);
  routeData.Values.Add("action", Request.QueryString.Get("action") ?? "Index");

  var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
  IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(requestContext, controllerName);
  controller.Execute(requestContext);
}

Trouvez plus de détails ici: https://stackoverflow.com/a/27354140/1435

1
Guillaume

J'ai découvert que si vous utilisez redirectMode = "ResponseRewrite", vous devez ajouter quelque chose dans la zone de réécriture du fichier web.config. Le problème, c'est quand votre site est cassé! Vous ne pouvez pas réécrire l'URL car votre site ne peut pas appeler le "virtual.aspx" qui gère votre réécriture!

0
Colin Wiseman

Dans mon cas particulier, ma page d'erreur avait une page maître qui avait un contrôle utilisateur qui tentait d'utiliser Session. Si Session n'est pas disponible, vous obtenez une HttpException: "L'état de session ne peut être utilisé que lorsque enableSessionState est défini sur true, soit dans un fichier de configuration, soit dans la directive Page." La solution la plus simple consiste à passer au html statique, la deuxième solution la plus simple consiste à utiliser une page d'erreur plus simple, la solution la plus difficile consiste à s'assurer incroyablement que votre page d'erreur ne fait aucune hypothèse (comme cette session ne lèvera pas d'exception, par exemple) et ne peut pas éventuellement sortir d'erreur.

0
David Eison