Sono interessato a gestire correttamente i guasti all'interno di un client di servizio REST WCF. Durante l'utilizzo di uno qualsiasi dei WebClient, WebRequest, o HttpWebRequest in questo modo:Come gestire/analizzare i guasti per un WCF Rest chiamato 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?
}
}
posso vedere in Fiddler che sto ottenendo un messaggio di "Guasto" (sia il default XML ben formattata perché includeExceptionDetailInFaults = true, o un guasto personalizzato tramite IErrorHandler :: ProvideFault). Tuttavia, viene lanciata solo una 500 Errore interno WebException.
Preferisco ottenere una FaultException lanciata sul client o almeno essere in grado di analizzare l'errore. Non stiamo usando "Service reference" quindi non c'è proxy (correggimi se esiste un modo migliore per farlo per un client WCF REST). Esiste un modo generico per analizzare quell'errore indipendentemente dal suo tipo effettivo T (FaultException) o anche per tipo specifico come punto di partenza? Grazie!
Sulla risposta da 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;
}
Questo sembra avvicinarmi. Su MessageFault.CreateFault() ricevo un reclamo di innerException sullo spazio dei nomi che non è ".../soap-envelope" invece di ".../envelope/none". Sei a conoscenza di un buon modo per aggirare il problema dello spazio dei nomi? Viene davvero dal server come ".../envelope/none". – crokusek
Ho modificato l'argomento in Message.CreateMessage() in MessageVersion.None anziché MessageVersion.Default e ho risolto il problema dello spazio dei nomi. Poiché sto iniziando con una WebException, ho finito per creare un messaggio dal flusso wex.Response. Pubblicherà ciò che ha finito per funzionare alla fine della domanda. – crokusek
Ricevi WebException anche dopo aver impostato FaultExceptionEnabled = true? –