2009-02-22 10 views
1

J'essaie de trouver un événement qui se déclenchera immédiatement après tous les gestionnaires d'événements Application_Error afin que je puisse modifier la réponse envoyée (jouer avec le code d'état et les en-têtes 'location' et créer un nouveau corps spécifiquement) en utilisant un HttpModule personnalisé.ASP.NET Post Application_Error Event

J'ai essayé accrochage dans Application_EndRequest (comme je l'ai lu que c'est le seul gestionnaire qui est garanti au feu), mais cela est trop tard dans le traitement de la demande de modifier les en-têtes de réponse et je reçois un HttpException:

Server cannot append header after HTTP headers have been sent. 

Répondre

2

Je pense qu'ASP.Net lance une nouvelle réponse après ApplicationError, juste pour une autre page de gestion des erreurs. Essayez de virer de bord dans cette réponse.

Mise à jour OK: Voici comment procéder! Je voulais m'assurer que nous pouvions joindre un gestionnaire d'erreur et que nous pouvions gérer l'événement avec élégance dans une page, donc nous ne pouvons pas rendre la dernière erreur de serveur nulle, et nous voulons aussi pouvoir ajouter des en-têtes !

En web.config, ajoutez:

<customErrors redirectMode="ResponseRewrite" mode="On"> 
    <error statusCode="500" redirect="~/ErrorHandler.aspx"/> 
</customErrors> 

Ou tout erreur que vous spécifiquement cherchent à attraper. Et sous httpModules:

<add name="ErrorModule" type="TestErrorLifecycle.ErrorModule, TestErrorLifecycle"/> 

Le code pour enregistrer l'erreur est dans ce module:

public class ErrorModule : IHttpModule 
{ 
    private volatile object locker = new object(); 

    public void Init(HttpApplication context) 
    { 
     context.Error += context_Error; 
    } 

    void context_Error(object sender, EventArgs e) 
    { 
     var app = sender as HttpApplication; 

     lock (locker) 
     { 
      assertLogDirectory(app.Server); 

      using (var fs = File.AppendText(app.Server.MapPath("~/logs/errorlog.txt"))) 
      { 
       var lastException = app.Server.GetLastError(); 
       if (lastException == null) throw new ApplicationException("Not expected..."); 
       fs.WriteLine(lastException.Message); 
      } 
     } 

     // we could also do a Request.Redirect() here... 
    } 

    private void assertLogDirectory(HttpServerUtility server) 
    { 
     var logdir = server.MapPath("~/logs/"); 
     if (!Directory.Exists(logdir)) 
      Directory.CreateDirectory(logdir); 
    } 

    public void Dispose() 
    { 
    } 
} 

Je viens d'écrire au système de fichiers. Vous pouvez utiliser des transactions de fichiers noyau ou un verrou exclusif ou autre, mais comme je sais que je n'écrirai dans ce fichier qu'à partir d'ici, j'ai choisi un simple sémaphore privé.

J'ajouté ceci dans Default.aspx.cs juste pour tester:

protected void Page_Load(object sender, EventArgs e) 
{ 
    throw new ApplicationException("wtf, something wrong??!"); 
} 

fichier créé avec ce ErrorHandler.aspx en elle (certaines parties omises pour la brièveté):

<body> 
    <h2>Error handler</h2> 
    <form id="form1" runat="server"> 
     <p>Last error: <asp:Label ID="lblError" runat="server" /></p> 
    </form> 
</body> 

Et voici la page classe:

public partial class ErrorHandler : Page 
{ 
    public ErrorHandler() 
    { 
     Load += ErrorHandler_Load; 
    } 

    private void ErrorHandler_Load(object sender, EventArgs e) 
    { 
     Response.AddHeader("X-TESTING", "Yes it works..."); 
     lblError.Text = Server.GetLastError() == null ? "noo, why is it null?!?" : Server.GetLastError().Message; 
    } 
} 

Enfin, je reçois ces en-têtes de réponse à la ErrorHandler.aspx:

Server: ASP.NET Development Server/9.0.0.0 
Date: Mon, 23 Feb 2009 00:37:45 GMT 
X-AspNet-Version: 2.0.50727 
X-TESTING: Yes it works... 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
Content-Length: 725 
Connection: Close 
200 OK 

Si vous essayez d'ajouter à Response.Headers-collection directement vous devez exécuter IIS en mode pipeline: http://forums.asp.net/p/1253457/2323117.aspx

J'espère que cela aide! Bravo Henrik

+0

Avez-vous des conseils sur la façon de procéder? –

+0

Oui, je vais faire un test. – Henrik

0

À moins que vous ne déplaciez tout le code sujette aux erreurs avant l'envoi de la réponse, vous ne pourrez pas résoudre ce problème. Si vous voulez faire cela, vous devez configurer un HttpHandler pour que tout le code soit exécuté avant d'envoyer toute information au client.

Il existe des moyens de réorganiser l'architecture pour renvoyer des informations au client. Sachant où l'application explose et l'exécute, essayez ... catch aidera.

+0

Vous avez manqué le point que j'ai peur - ce n'est pas le cas de moi étant incapable de piéger une exception, plus que je dois être en mesure de modifier la réponse d'erreur vers le client. –

+0

Je comprends le point, mais sans modifier l'implémentation par défaut, vous ne pouvez pas intercepter avec un gestionnaire d'erreur générale et modifier le flux, car les en-têtes sont déjà envoyés. Si vous voulez gérer vous-même le pipeline ASP.NET, vous pouvez le faire. –