我有一个asp.NET Web服务(不是WCF,而是带有WebMethods的经典.asmx),它会抛出异常。所有异常都来自两个基本异常类之一(两者都派生自Exception):
public class InputException : Exception
{
....
}
public class FatalException : Exception
{
....
}
public class NoFilesFound: FatalException
{
....
}
....
Web服务现在根据需要抛出异常。在我的客户端代码中,我可以捕获异常并看到如下消息:
Server was unable to process request. ---> There were no files found
但是异常是FaultException类型(当我在捕获的异常上执行.GetType()时看到)。调用客户端需要能够区分InputException和FatalException(并且最佳地区分各个派生的但却不那么重要)。现在唯一的方法是解析消息,在“--->”之前删除文本并打开文本。这显然不是最佳的。
我知道我可以使用自定义代码抛出SoapExceptions但我希望尽可能避免这种情况。此外,它似乎是为那些处理XML的人而设计的,但是我们所有的web服务代码都没有触及XML,因为它已经为我们反序列化了。
简而言之,有没有办法让我从Web服务中抛出自定义异常,并让调用客户端能够区分异常?
答案 0 :(得分:7)
处理此问题的正确方法是使用SoapException。所以你基本上会捕获服务上所有可能的异常,然后将它们转换为SoapException(我链接的文档包含一个示例),然后抛出这个自定义异常而不是抛出这个SoapException并包含你感兴趣的信息故障的Detail XML节点。
然后,当在客户端上调用服务时,您将能够捕获此SoapException并分析Detail XML节点以收集有关服务器上发生的故障的确切原因的更多详细信息。
在WCF中,所有这些手动生成的故障节点都非常简单,只需使用数据合同并捕获FaultException<SomeFaultContract>
。
让我们举个例子。假设您有以下服务方法抛出SoapException并在Details节点中提供有关错误的详细信息:
[WebMethod]
public string HelloWorld()
{
var doc = new XmlDocument();
var node = doc.CreateNode(
XmlNodeType.Element,
SoapException.DetailElementName.Name,
SoapException.DetailElementName.Namespace
);
// you could actually use any sub nodes here
// and pass even complex objects
node.InnerText = "no files found";
throw new SoapException(
"Fault occurred",
SoapException.ClientFaultCode,
Context.Request.Url.AbsoluteUri,
node
);
}
在使用它时,您可以在客户端上捕获此SoapException:
using (var client = new WebService1())
{
try
{
var result = client.HelloWorld();
}
catch (SoapException ex)
{
var detail = ex.Detail;
// detail.InnerText will contain the detail message
// as detail is an XmlNode if on the server you have
// provided a complex XML you would be able to fetch it here
}
}
就您的InputException
,FatalException
和NoFilesFound
例外情况而言,它们很好,但它们应保留在服务器上。在您的Web方法中捕获它们并构建一个适当的SoapException
,客户端将能够理解何时使用该服务。