Los errores de SOAP transportan información de condición de errores desde un servicio a un cliente y, en caso de comunicación dúplex, desde un cliente a un servicio de manera interoperable. Normalmente, un servicio define el contenido del error personalizado y especifica qué operaciones pueden devolverlos. (Para más información, consulte Definición y especificación de errores). En este tema, se analiza cómo un servicio o cliente dúplex puede enviar esos errores cuando se ha producido la condición de error correspondiente y cómo una aplicación de servicio o cliente administra estos errores. Para información general sobre los procesos de control de errores en las aplicaciones de Windows Communication Foundation (WCF), consulte Especificación y control de errores en contratos y servicios.
Envío de errores SOAP
Los errores de SOAP declarados son aquéllos en los que una operación tiene System.ServiceModel.FaultContractAttribute que especifica un tipo de error de SOAP personalizado. Los errores de SOAP no declarados son aquéllos que no se especifican en el contrato para una operación.
Envío de errores declarados
Para enviar un error de SOAP declarado, detecte la condición de error para la que el error de SOAP es adecuado y genere una nueva System.ServiceModel.FaultException<TDetail>, donde el parámetro de tipo es un nuevo objeto del tipo especificado en FaultContractAttribute para esa operación. El ejemplo de código siguiente muestra el uso de FaultContractAttribute para especificar que la operación SampleMethod puede devolver un error de SOAP con el tipo de detalle de GreetingFault.
<OperationContract, FaultContractAttribute(GetType(GreetingFault), Action:="http://www.contoso.com/GreetingFault", ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
Function SampleMethod(ByVal msg As String) As String
Para transportar la información de error GreetingFault al cliente, detecte la condición de error adecuada y genere una nueva System.ServiceModel.FaultException<TDetail> de tipo GreetingFault con un nuevo objeto GreetingFault como el argumento, como en el ejemplo de código siguiente. Si el cliente es una aplicación cliente WCF, experimenta esto como una excepción administrada donde el tipo es System.ServiceModel.FaultException<TDetail> de tipo GreetingFault.
throw new FaultException<GreetingFault>(new GreetingFault("A Greeting error occurred. You said: " + msg));
Throw New FaultException(Of GreetingFault)(New GreetingFault("A Greeting error occurred. You said: " & msg))
End If
Envío de errores no declarados
Enviar errores no declarados puede ser muy útil para diagnosticar y depurar rápidamente los problemas en las aplicaciones WCF, pero su utilidad como herramienta de depuración es limitada. Más generalmente, se recomienda al depurar que utilice la propiedad ServiceDebugBehavior.IncludeExceptionDetailInFaults. Al establecer este valor en true, los clientes experimentan tales errores como excepciones FaultException<TDetail> de tipo ExceptionDetail.
Importante
Dado que las excepciones administradas pueden exponer información interna de la aplicación, establecer ServiceBehaviorAttribute.IncludeExceptionDetailInFaults o ServiceDebugBehavior.IncludeExceptionDetailInFaults en true puede permitir que los clientes WCF obtengan información sobre las excepciones de operaciones de servicio internas, incluida la información de identificación personal u otro tipo de información confidencial.
En clientes WCF, los errores de SOAP que se producen durante la comunicación que son de interés para las aplicaciones cliente se generan como excepciones administradas. Aunque hay muchas excepciones que pueden producirse durante la ejecución de cualquier programa, las aplicaciones que usan el modelo de programación de cliente WCF pueden esperar administrar excepciones de uno de los dos tipos siguientes como resultado de la comunicación.
Las excepciones FaultException se producen cuando un agente de escucha recibe un error que no se espera o especifica en el contrato de operación; normalmente esto sucede cuando se depura la aplicación y el servicio tiene la propiedad ServiceDebugBehavior.IncludeExceptionDetailInFaults establecida en true.
Las excepciones FaultException<TDetail> se producen en el cliente cuando se recibe un error de SOAP especificado en el contrato de la operación en respuesta a una operación bidireccional (es decir, un método con un atributo OperationContractAttribute con IsOneWay establecido en false).
Por supuesto, se producen otras excepciones. Entre las excepciones no esperadas se incluyen errores catastróficos como System.OutOfMemoryException; normalmente las aplicaciones no deberían detectar ese tipo de métodos.
Detectar excepciones de errores en el orden correcto
Puesto que FaultException<TDetail> deriva de FaultException, y FaultException deriva de CommunicationException, es importante detectar estas excepciones en el orden apropiado. Por ejemplo, si tiene un bloque de intento/detección en el que primero detecta CommunicationException, todos los errores SOAP especificados y no especificados se administran ahí; los bloques de detección posteriores para administrar una excepción FaultException<TDetail> personalizada nunca se invocan.
Recuerde que una operación puede devolver un número indefinido de errores especificados. Cada error es de un tipo único y se ha de administrar separadamente.
Administre las excepciones al cerrar el canal
La mayor parte del análisis anterior tiene que ver con los errores enviados en el curso del procesamiento de mensajes de aplicaciones, es decir, mensajes enviados explícitamente por el cliente cuando la aplicación de cliente llama a las operaciones en el objeto de cliente WCF.
Incluso con la disposición de objetos locales, el objeto puede elevar o enmascara excepciones que tienen lugar durante el proceso de reciclaje. Algo similar puede producirse al utilizar objetos de cliente WCF. Al llamar a operaciones, está enviando mensajes a través de una conexión establecida. Cerrar el canal puede producir excepciones si la conexión no se puede cerrar limpiamente o ya está cerrada, aun cuando todas las operaciones hayan devuelto correctamente.
Normalmente, los canales de objeto de cliente se cierran de una de las siguientes maneras:
Cuando la aplicación de cliente llama a una operación que es una operación de finalización para una sesión.
En todos los casos, cerrar el canal indica al canal que comience a cerrar todos los canales subyacentes que puedan estar enviando mensajes para admitir una funcionalidad compleja en el nivel de la aplicación. Por ejemplo, cuando un contrato requiere sesiones, un enlace intenta establecer una sesión mediante el intercambio de mensajes con el canal del servicio hasta que se establezca una sesión. Cuando se cierre el canal, el canal de la sesión subyacente notifica al servicio que la sesión se ha terminado. En este caso, si el canal ya se ha anulado, cerrado o es inutilizable (por ejemplo, cuando se desconecta un cable de red), el canal de cliente no puede informar al canal del servicio que se finaliza la sesión y es posible que se produzca una excepción.
Anule el canal si fuese necesario
Dado que cerrar el canal también puede producir excepciones, se recomienda que además de detectar las excepciones de error en el orden correcto, es importante anular el canal que se utilizó para realizar la llamada en el bloque de detección.
Si el error transporta información de error específica de una operación y sigue siendo posible que otros puedan utilizarla, no hay ninguna necesidad de anular el canal (aunque estos casos son aislados). En el resto de casos, se recomienda que anule el canal. Para un ejemplo que muestra todos estos puntos, consulte Excepciones esperadas.
El siguiente ejemplo de código muestra cómo administrar las excepciones de errores de SOAP en una aplicación de cliente básica, incluyendo un error declarado y uno no declarado.
Nota
Este código de ejemplo no utiliza la construcción using. Dado que el cierre de canales puede producir excepciones, se recomienda que las aplicaciones creen primero un cliente WCF, y, a continuación, abran, utilicen y cierren el cliente WCF en el mismo bloque de intento. Para detalles, consulte Introducción a un cliente WCF y Uso de Close y Abort para liberar los recursos del cliente WCF.
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;
public class Client
{
public static void Main()
{
// Picks up configuration from the config file.
SampleServiceClient wcfClient = new SampleServiceClient();
try
{
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));
Console.WriteLine("Press ENTER to exit:");
Console.ReadLine();
// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (FaultException<GreetingFault> greetingFault)
{
Console.WriteLine(greetingFault.Detail.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (FaultException unknownFault)
{
Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
Console.ReadLine();
wcfClient.Abort();
}
}
}
Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation
Public Class Client
Public Shared Sub Main()
' Picks up configuration from the config file.
Dim wcfClient As New SampleServiceClient()
Try
' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()
Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))
Console.WriteLine("Press ENTER to exit:")
Console.ReadLine()
' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
Console.ReadLine()
wcfClient.Abort()
Catch greetingFault As FaultException(Of GreetingFault)
Console.WriteLine(greetingFault.Detail.Message)
Console.ReadLine()
wcfClient.Abort()
Catch unknownFault As FaultException
Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
Console.ReadLine()
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
Console.ReadLine()
wcfClient.Abort()
End Try
End Sub
End Class
En este módulo se explora el uso de excepciones y el proceso de control de excepciones en aplicaciones de consola de C#. Las actividades prácticas proporcionan experiencia en la implementación de patrones de control de excepciones para varios escenarios de codificación.