Close et Abort libèrent les ressources de manière sécurisée lorsque les connexions réseau ont été supprimées

L’exemple UsingUsing illustre l’utilisation des méthodes Close et Abort pour nettoyer les ressources lors de l’utilisation d’un client typé. L’instruction using provoque des exceptions lorsque la connexion réseau n’est pas robuste. Cet exemple est basé sur l’exemple Getting Started qui implémente un service de calculatrice. Dans cet exemple, le client est une application console (.exe) et le service est hébergé par les services IIS (Internet Information Services).

Notes

La procédure d'installation ainsi que les instructions de génération relatives à cet exemple figurent à la fin de cette rubrique.

Cet exemple contient deux des problèmes fréquents susceptibles de survenir lorsque l'instruction « using » C# est utilisée avec les clients typés ainsi que le code permettant de procéder au nettoyage adéquat après la survenue d'exceptions.

L'instruction « using » C# provoque l'appel de Dispose(). Cette méthode est identique à la méthode Close(), laquelle peut lever des exceptions lorsqu'une erreur réseau se produit. L'appel de Dispose() se produit de manière implicite au niveau de l'accolade fermante du bloc « using », cette source d'exceptions a peu de chance d'être remarquée par une personne lisant le code ou par la personne chargée de le rédiger. Cela représente une source potentielle d'erreurs d'application.

Le premier problème, illustré dans la méthode DemonstrateProblemUsingCanThrow, réside dans le fait que l'accolade fermante lève une exception et que le code figurant après cette accolade ne s'exécute pas :

using (CalculatorClient client = new CalculatorClient())
{
    ...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");

Même si rien à l'intérieur du bloc « using » ne provoque la levée d'une exception ou si toutes les exceptions à l'intérieur de ce bloc sont interceptées, le code Console.WriteLine peut ne pas s'exécuter, l'appel implicite de Dispose() risquant de lever une exception.

Le second problème, illustré dans la méthode DemonstrateProblemUsingCanThrowAndMask, est une autre conséquence du problème résultant de la levée d'une exception par l'accolade fermante :

using (CalculatorClient client = new CalculatorClient())
{
    ...
    throw new ApplicationException("Hope this exception was not important, because "+
                                   "it might be masked by the Close exception.");
} // <-- this line might throw an exception.

La méthode Dispose() survenant à l'intérieur d'un bloc « finally », l'exception ApplicationException ne sera pas visible en dehors du bloc « using » si la méthode Dispose() échoue. Si le code externe doit savoir à quel moment l'exception ApplicationException survient, le bloc « using » risque de poser un problème, car il masque cette exception.

Enfin, cette exemple illustre comment procéder à un nettoyage adéquat lors de la survenue d'exceptions dans DemonstrateCleanupWithExceptions. Pour ce faire, un bloc essai/interception est utilisé pour signaler les erreurs et appeler la méthode Abort. Consultez l'exemple Expected Exceptions pour plus d'informations sur la manière d'intercepter des exceptions à partir d'appels du client.

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

Notes

Instruction « using » et ServiceHost : de nombreuses applications d'auto-hébergement ne se contentent pas seulement d'héberger des services et l'appel de la méthode ServiceHost.Close lève rarement une exception. Par conséquent, ces applications peuvent utiliser l'instruction « using » avec ServiceHost. Toutefois, n'oubliez pas que l'appel de la méthode ServiceHost.Close peut lever une exception CommunicationException. Par conséquent, si votre application continue à s'exécuter après la fermeture de ServiceHost, vous devez éviter d'utiliser l'instruction « using » et vous conformer au modèle mentionné précédemment.

Lorsque vous exécutez l'exemple, les exceptions et réponses d'opération s'affichent dans la fenêtre de console du client.

Le processus du client exécute trois scénarios qui essaient tous d'appeler Divide. Le premier scénario contient le code ignoré à cause de l'exception levée par la méthode Dispose(). Le deuxième scénario contient une exception importante masquée à cause de l'exception levée par la méthode Dispose(). Le troisième scénario illustre le processus de nettoyage adéquat.

Le processus client est censé donner le résultat suivant :

=
= Demonstrating problem:  closing brace of using statement can throw.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating problem:  closing brace of using statement can mask other Exceptions.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating cleanup with Exceptions.
=
Calling client.Add(0.0, 0.0);
        client.Add(0.0, 0.0); returned 0
Calling client.Divide(0.0, 0.0);
Got System.ServiceModel.CommunicationException from Divide.

Press <ENTER> to terminate client.

Pour configurer, générer et exécuter l'exemple

  1. Assurez-vous d’avoir effectué la Procédure d’installation unique pour les exemples Windows Communication Foundation.

  2. Pour générer l’édition C# ou Visual Basic .NET de la solution, conformez-vous aux instructions figurant dans Building the Windows Communication Foundation Samples.

  3. Pour exécuter l’échantillon dans une configuration à un ou plusieurs ordinateurs, conformez-vous aux instructions fournies dans Exécution des échantillons Windows Communication Foundation.