Evitar problemas mediante una declaración de instrucción
Este ejemplo muestra cómo no debería utilizar el C# "utilizando" la instrucción para limpiar automáticamente los recursos al utilizar un cliente especificado. Este ejemplo se basa en Ejemplo de introducción que implementa un servicio de calculadora. En este ejemplo, el cliente es una aplicación de consola (.exe) e Internet Information Services (IIS) hospeda el servicio.
Nota: |
---|
El procedimiento de instalación y las instrucciones de compilación de este ejemplo se encuentran al final de este tema. |
Este ejemplo muestra dos de los problemas comunes que se producen al utilizar el C# "utilizando" la instrucción con clientes escritos a máquina, así como el código que limpia correctamente después de las excepciones.
La instrucción C# "utilizando" resulta en una llamada a Dispose(). Esto es igual que Close(), que puede producir las excepciones cuando se produce un error en la red. Dado que la llamada a Dispose() ocurre implícitamente en la llave de cierre del bloque "utilizando", es probable que este origen de excepciones pase inadvertido a las personas que escriben el código y a las que leen el código. Esto representa un origen potencial de errores de aplicación.
El primer problema, mostrado en el método DemonstrateProblemUsingCanThrow
, es que la llave de cierre inicia una excepción y el código no se ejecuta después de que la llave se cierre:
using (CalculatorClient client = new CalculatorClient())
{
...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");
Aun cuando nada dentro del bloque que se está utilizando produzca una excepción , o aunque todas las excepciones dentro del bloque que está siendo utilizando la detecten, Console.Writeline no podrían ocurrir porque la llamada implícita Disposea la llave de cierre podría producir una excepción.
El segundo problema, mostrado en el método DemonstrateProblemUsingCanThrowAndMask
, es que otra implicación de la llave de cierre produzca una excepción:
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.
Dado que Dispose() se produce dentro de un bloque "finalmente", el ApplicationException nunca se ve fuera del bloque que se está utilizando si se produce un error Dispose() . Si el código fuera de debe conocer sobre cuando ApplicationException produce, la construcción "utilizando" puede producir los problemas enmascarando esta excepción.
Finalmente, el ejemplo muestra correctamente cómo limpiar cuando se producen excepciones en DemonstrateCleanupWithExceptions
. Esto utiliza un bloque prueba try/catch para crear informes errores y llamarAbort. Vea la muestraExcepciones esperadas para obtener más detalles sobre cómo detectar las excepciones de las llamadas del cliente.
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
Nota: |
---|
La instrucción en uso y ServiceHost: Muchas aplicaciones hospedadas en sí mismas hacen poco más que hospedar un servicio y ServiceHost.Close raramente produce una excepción, por lo que tales aplicaciones pueden utilizar sin ningún riesgo la instrucción en uso con ServiceHost. Sin embargo, sea consciente que ServiceHost.Close puede iniciar unaCommunicationException, por lo que si su aplicación continúa después de cerrar ServiceHost, debería evitar la instrucción en uso y seguir el modelo previamente proporcionado. |
Al ejecutar el ejemplo, las respuestas y excepciones de la operación se muestran en la ventana de la consola del cliente.
El proceso de cliente ejecuta tres escenarios, cada uno de los cuales intentan llamar Divide
. El primer escenario muestra un código que está omitido debido a una excepción de Dispose(). El segundo escenario muestra una excepción importante enmascarándose debido a una excepción de Dispose(). El tercer escenario muestra el proceso de limpieza correcto.
El resultado esperado del proceso de cliente es:
=
= 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.
Para configurar, compilar y ejecutar el ejemplo
Asegúrese de realizar los Procedimiento de instalación única para los ejemplos de Windows Communication Foundation.
Para compilar el código C# o Visual Basic .NET Edition de la solución, siga las instrucciones de Compilación de los ejemplos de Windows Communication Foundation.
Para ejecutar el ejemplo en una configuración con un único equipo o con varios, siga las instrucciones de Running the Windows Communication Foundation Samples.
Nota: |
---|
Puede que los ejemplos ya estén instalados en su equipo. Compruebe el siguiente directorio (valor predeterminado) antes de continuar.
<InstallDrive>:\WF_WCF_Samples
Si no existe este directorio, vaya a la página de ejemplos de Windows Communication Foundation (WCF) y Windows Workflow Foundation (WF) Samples para .NET Framework 4 para descargar todos los ejemplos de Windows Communication Foundation (WCF) y WF. Este ejemplo se encuentra en el siguiente directorio.
<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Client\UsingUsing
|