cro*_*sek 5 rest wcf client exception fault
我有兴趣在WCF REST服务客户端中正确处理故障.在使用任何WebClient,WebRequest或HttpWebRequest时,如下所示:
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?
}
}
Run Code Online (Sandbox Code Playgroud)
我可以在Fiddler中看到我收到格式良好的XML"Fault"消息(默认是因为includeExceptionDetailInFaults = true,或者是通过IErrorHandler :: ProvideFault的自定义错误).但是,仅抛出500个内部错误WebException.
我宁愿在客户端上抛出一个FaultException,或者至少能够解析Fault.我们没有使用"服务参考",因此没有代理(如果有更好的方法为REST WCF客户端执行此操作,请更正我).是否有一种通用的方法来解析该错误,无论其实际类型为T(FaultException),还是将特定类型作为起点?谢谢!
根据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;
}
Run Code Online (Sandbox Code Playgroud)
故障是SOAP协议的一部分,在REST方案中不可用.我不相信任何WCF基础设施都支持开箱即用的功能.
您可以在WebHttp行为配置中设置FaultExceptionEnabled = true以获取FaultException而不是500错误.
但是,您也可以这样做(我在某些测试场景中已经这样做了).这种方法依赖于提前知道故障中预期的FaultDetail类型.
bool isFault;
if (message.Version == MessageVersion.None)
{
//Need to determine for ourselves if this is a fault;
using (MessageBuffer buffer = message.CreateBufferedCopy(65536))
{
message.Close();
message = buffer.CreateMessage();
using (Message message2 = buffer.CreateMessage())
{
using (XmlDictionaryReader reader = message2.GetReaderAtBodyContents())
{
isFault = reader.IsStartElement("Fault", "http://schemas.microsoft.com/ws/2005/05/envelope/none");
}
}
}
}
else
{
// For SOAP messages this is done for us
isFault = message.IsFault;
}
if (isFault)
{
var fault = MessageFault.CreateFault(message, 65536);
MyServiceFault detail = null;
if (fault.HasDetail)
{
// The only thing we can possible have as detail is an MyServiceFault
detail = fault.GetDetail<MyServiceFault>();
}
FaultException ex = new FaultException<MyServiceFault>(detail, fault.Reason, fault.Code);
throw ex;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5216 次 |
| 最近记录: |