Estoy interesado en manejar correctamente las fallas dentro de un cliente de WCF REST Service. Durante el uso de cualquiera de cliente Web, WebRequest, o HttpWebRequest así:Cómo manejar/analizar Fallas para un repositorio de WCF llamado usando WebClient
try
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
// ...process...
}
catch (WebException wex)
{
string exMessage = wex.Message;
if (wex.Response != null)
{
using (StreamReader r = new StreamReader(wex.Response.GetResponseStream()))
exMessage = r.ReadToEnd();
// the fault xml is available here, really need to parse? and how?
}
}
que puedo ver en Fiddler que estoy recibiendo un mensaje de "Fallo" (ya sea el predeterminado XML con un formato agradable porque includeExceptionDetailInFaults = true, o un fallo de encargo a través de IErrorHandler :: ProvideFault). Sin embargo, solo se lanza un error interno de 500 WebException.
Prefiero obtener una FaultException lanzada en el cliente o al menos poder analizar la falla. No usamos "Referencia de servicio", por lo que no hay proxy (corrígeme si hay una forma mejor de hacerlo para un cliente REST WCF). ¿Existe una forma genérica de analizar ese error independientemente de su tipo real T (FaultException) o incluso para un tipo específico como punto de partida? ¡Gracias!
Sobre la respuesta de degorolls:
public SomeContract ThrowErrorTest()
{
try
{
return TryCatchExtractAndRethrowFaults<SomeContract>(() =>
{
// Call web service using WebClient, HttpWebRequest, etc.
return SomeContract;
});
}
catch (FaultException<CustomFault> fexCustom)
{
Dbg.WriteLine(fexCustom.Message);
}
catch (FaultException fex)
{
Dbg.WriteLine(fex.Message);
}
catch (WebException wex)
{
Dbg.WriteLine(wex.Message);
}
catch (Exception ex)
{
Dbg.WriteLine(ex.Message);
}
return null;
}
static public T TryCatchExtractAndRethrowFaults<T>(Func<T> doWebRequest)
{
try
{
return doWebRequest();
}
catch (WebException wex)
{
FaultException fe = ConvertWebExceptionIntoFault(wex);
if (fe != null)
throw fe;
throw; // not a fault, just re-throw
}
}
static protected FaultException ConvertWebExceptionIntoFault(WebException wex)
{
if (wex.Response == null)
return null;
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(
wex.Response.GetResponseStream(),
new XmlDictionaryReaderQuotas());
Message msg = Message.CreateMessage(MessageVersion.None, "ParseFaultException", xdr);
// If the start element of the message is "Fault" convert it into a FaultException
//
using (MessageBuffer msgBuffer = msg.CreateBufferedCopy(65536))
using (Message msgCopy = msgBuffer.CreateMessage())
using (XmlDictionaryReader reader = msgCopy.GetReaderAtBodyContents())
if (reader.IsStartElement("Fault"))
{
// Must make a copy for the converter
msg.Close();
msg = msgBuffer.CreateMessage();
return ConvertMessageToFault(msg);
}
return null;
}
static FaultException ConvertMessageToFault(Message msg)
{
EnvelopeVersion ev = msg.Version.Envelope;
var fault = MessageFault.CreateFault(msg, 65536);
if (fault.HasDetail)
{
string faultName = fault.GetReaderAtDetailContents().Name;
switch (faultName)
{
case "ExceptionDetail": // handle the default WCF generated fault
ExceptionDetail exDetail = fault.GetDetail<ExceptionDetail>();
return new FaultException<ExceptionDetail>(exDetail, fault.Reason, fault.Code);
case "CustomFault": // handle custom faults
CustomFault cstmDetail = fault.GetDetail<CustomFault>();
return new FaultException<CustomFault>(cstmDetail, fault.Reason, fault.Code);
default:
throw new Exception("Unrecognized fault detail '" + faultName +
"' while re-constructing fault.");
}
}
return null;
}
Parece que eso me acerca. En MessageFault.CreateFault() recibo una queja innerException sobre el espacio de nombres que no es ".../soap-envelope" en lugar de ".../envelope/none". ¿Conoces una buena forma de solucionar el problema del espacio de nombres? Realmente proviene del servidor como ".../envolvente/ninguno". – crokusek
Cambié el argumento a Message.CreateMessage() a MessageVersion.None en lugar de MessageVersion.Default y eso resolvió el problema del espacio de nombres. Como empiezo con una WebException, terminé creando un mensaje desde la secuencia wex.Response. Publicaremos lo que terminó funcionando al final de la pregunta. – crokusek
¿Obtiene WebException incluso después de establecer FaultExceptionEnabled = true? –