24 votes

Pourquoi mon pool d'applications IIS7 s'arrête-t-il après une exception dans une DLL appelée à partir d'une page ASP.NET?

J'ai lu les publications Problème de fermeture du pool d'applications ASP.NET et IIS 7.5 : problème avec le pool d'applications mais elles n'ont pas répondu à ma question.

J'ai une page C# ASP.NET qui, en code-behind, instancie une classe à partir d'une DLL fournie via le répertoire BIN, puis appelle une méthode sur cette instance. La méthode à l'intérieur de la DLL lance System.ArgumentException en raison d'une colonne inexistante dans un objet DataRow. Le journal des événements affiche l'erreur suivante :

Source : ASP.NET 2.0.50727.0
ID de l'application : /LM/W3SVC/1/ROOT/...
ID du processus : 9476
Exception : System.ArgumentException
Message : La colonne 'someColumn' n'appartient pas à la table.
StrackTrace : 

Le code d'appel dans la page ASP.NET enveloppe l'appel de méthode dans un bloc générique try-catch. Lorsque je demande la page, cela provoque le blocage du pool d'applications correspondant de mon instance IIS et mon site web n'est plus disponible (Erreur 503). Je dois redémarrer manuellement le pool d'applications et le site fonctionne à nouveau.

Mise à jour Comme demandé, le bloc try catch du code-behind ASP.NET :

try
{
    SomeExternalClass someExternalClass = new SomeExternalClass();
    someExternalClass.SomeMethod( someId );
}
catch( Exception ex )
{
    // "smp" est une instance de "StatusMessagePanel", un contrôle que nous utilisons sur toutes les pages pour afficher les informations d'erreur, essentiellement un conteneur div avec une icône.
    smp.ShowError( ex.Message ); 
}

Maintenant ma question est pourquoi une exception relativement "simple" comme System.ArgumentException qui est lancée en essayant d'accéder à une colonne DataRow inexistante, bloque tout le site web? Ni le bloc générique try-catch de la page ASP.NET n'aide, ni cela devrait être la raison de rendre complètement le site web indisponible, ou est-ce une mauvaise hypothèse? Je n'aurais jamais pensé que cela pourrait en fait mettre le serveur hors service.

En anticipant les gens me disant que je devrais vérifier l'existence des colonnes avant d'y accéder : je sais cela et le code hérité a maintenant été modifié, mais ce n'est pas ma question telle que décrite ci-dessus, je voudrais savoir pourquoi les conséquences sont si drastiques.

Mise à jour 2

La méthode en question appelée à l'intérieur de la DLL démarre un thread qui est enveloppé dans un bloc try-catch :

[...]
try
{
    ThreadStart starter = () => CreateReport(...)
    Thread thread = new Thread( starter );
    thread.Start();
    if( !thread.Join( TimeSpan.FromMinutes( 15 ) ) )
    {
        // Enregistrer un avertissement de dépassement de délai
    }
    else
    {
        // Enregistrer des informations sur la génération de rapport réussie
    }
}
catch( Exception ex )
{
    // Enregistrer des informations d'erreur
}

22voto

Zachary Yates Points 4952

Très probablement, votre pool d'application est automatiquement arrêté par la fonctionnalité de Protection contre les échecs rapides de IIS, comme vous le remarquez dans les questions liées. Si vous vérifiez vos journaux d'événements, il peut y avoir plusieurs exceptions non gérées qui sont lancées successivement.

En d'autres termes, un nombre suffisant d'exceptions non gérées dans un laps de temps configurable (le paramètre par défaut est de 5 en 5 minutes) arrêtera le AppPool, provoquant la réponse 503 Service Unavailable.

Le but de cette fonctionnalité est que si vous avez une application défectueuse, vous ne voulez probablement pas qu'elle redémarre automatiquement à chaque demande ultérieure, consommant des ressources et risquant de corrompre des données.

Je dois admettre que ce n'est pas non plus le comportement "par défaut" que j'aurais attendu.

Consultez l'explication de Rick Stahl, elle est un peu plus détaillée.

Pour résoudre ce problème, vous devez attraper l'exception, ou empêcher que l'exception ne soit lancée (comme le suggère @leppie). Les exceptions non gérées sont censées arrêter l'ensemble du processus en cours d'exécution (ce qui signifie cette demande/processus de travail unique, pas IIS) - cela facilite beaucoup le débogage du code .Net, car il n'occulte pas les erreurs ou ne bloque pas simplement l'application.

Notez que cela a été changé en .Net 2.0 :

http://msdn.microsoft.com/en-us/library/ms228965.aspx
http://support.microsoft.com/kb/911816

Mise à jour
Selon votre mise à jour ci-dessus, je ne pense pas que votre exception soit réellement attrapée, si elle est lancée depuis CreateReport(). Cette méthode s'exécute sur un thread séparé :

exception still thrown

Vous avez besoin d'un bloc try-catch dans le corps de CreateReport() s'il n'existe pas déjà :

public static void CreateReport() {
    try {
        throw new Exception("reducto");
    } catch {
        Console.WriteLine("done did.");
    }
}

4voto

Guish Points 879

Il m'est arrivé une fois. L'erreur réelle (dans mon cas) était un dépassement de pile qui fermait le pool.

Il semble que IIS se protège de la consommation excessive de ressources.

J'ai trouvé le problème en utilisant DebugDiag.

Voici où j'ai commencé : http://www.webdebug.net/index.php/2012/12/collect-iis-crash-dump-with-debugdiag/

J'aimerais comprendre pourquoi une exception dans une DLL externe peut entraîner l'arrêt du pool d'application IIS, même si l'exception est capturée à l'intérieur de la DLL et également lors de l'appel de la méthode de la DLL depuis le code derrière la page ASP.NET.

La dll externe s'exécute également dans votre pool d'applications. Un crash majeur dans cette dll entraînera également un crash de votre pool d'applications. Certaines exceptions ne peuvent pas être gérées et l'exception de stackoverflow en fait partie. Le sujet est discuté ici. Peut-être que c'est ce qui s'est passé dans votre cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X