Web服务应该抛出异常还是返回结果对象?

12

我不确定在Web服务中抛出异常是否是个好主意。如果没有堆栈跟踪,也许我并不会介意这一点。

我研究了几种实现方法,但似乎并没有共识。比如,CampaignMonitor返回一个Result对象,而其他人则不是这样。

从架构上看,我不确定返回一个Return对象是否有意义,毕竟异常就是异常,但我喜欢Return对象更为优雅的解决方案,这对最终用户来说更友好。

是否有更好的解决方案?

编辑

顺便说一下,我正在使用ASMX Web服务,无法打开CustomErrors选项。


实际上,我相信消除异常细节的方法是通过在web.config中调整customErrors标签。信不信由你。 - John Saunders
@John:是的,这就是我在这里说的。不幸的是,这对我来说不是一个选项。否则,这对我来说将是一个更简单的问题 :(. - Ryan Tomlinson
7个回答

8

不要因为你在一个Web服务中而混淆了问题。那只是一些实现细节。

使用你的正常异常处理策略。最佳实践是不要在低级别代码中捕获异常,除非你可以在那里解决该异常并正常继续。异常应该被抛到表示层,以便用户可以被告知错误。

因此,对于Web服务,通常会抛出异常(结果是SoapFault)。这允许调用客户端代码使用其内置的异常处理标准来处理它。


@Maladon:这是一个很好的答案,除了在层边界上。通常,在层边界上,策略会发生变化,特别是在服务层。对于WCF而言,层边界是捕获异常“A”并将其替换为FaultException<AFaUlt>的好地方,这将发送SOAP故障AFault。顺便说一句,没有堆栈跟踪。ASMX不支持正确的错误处理;这是停止使用它的另一个原因。 - John Saunders

7
你在谈论哪个调用堆栈?你尝试过这个方法吗?
在ASMX和WCF服务中,未捕获的异常将被转换为SOAP故障。在两种情况下,它们都可以配置为不包含任何调用堆栈。事实上,在WCF中,这是默认设置。
因此,返回此类错误的正确方式是通过故障。生成故障的一种方法是抛出异常而不处理它。

2
阅读有关SOAP故障的内容。这是向客户端返回任意详细信息的标准方式。在ASMX Web服务中,您必须手动在SoapException实例的Detail属性中返回它们,但如果您必须使用ASMX,则这是正确的方法。当然,更好的方法是使用WCF。此外,不要将其视为通知用户异常。异常是实现细节。您正在通知他们有一个故障。 - John Saunders
这不是我观察到的情况。我的 ASMX web 服务在默认设置下都返回堆栈跟踪信息,这让我很疯狂。而且当一系列服务相互调用时,最后一个服务抛出异常时,客户端会收到所有参与服务的巨大堆栈跟踪信息(以 SoapException 的形式呈现,其中 Message 属性包含连接文本的堆栈跟踪)。这太可怕了,我不知道如何关闭它。 - GSerg
@GSerg:你可以通过以下两种方式之一关闭它:1. 切换到 WCF,在那里你可以控制细节是否在消息中,2. 修复你的代码以避免出现问题。 - John Saunders
@JohnSaunders出于兼容性原因,我不会转换到WCF,而且代码也没有问题。当检测到错误参数时,我会自愿抛出异常,并提供有用的“Message”。我知道我可以返回一个带有“Success = false”的虚拟回复对象,但这很愚蠢,正如您在答案中所说,正确的方法是抛出异常。我仍然无法相信关闭堆栈跟踪是不可能的-在这种情况下,所有公开暴露的ASMX服务的客户端都可以经常窥视其源代码结构? - GSerg
@GSerg:SOAP网络服务(包括ASMX和WCF)不支持传递异常。它们支持返回故障,但这并不是同样的东西。 - John Saunders
显示剩余3条评论

2

一种方法是将系统错误和业务错误分开。(系统错误:例如格式不正确的请求、用户未经授权等;业务错误:例如方法UpdateCars导致错误,用户没有任何汽车)。

在发生业务错误时,返回一个包含错误描述的响应对象;在发生系统错误时,抛出异常。


1
SOAP规范提供了故障返回错误条件的功能,应该使用它们。否则,您的客户将不得不记住检查错误返回值,并且无法使用其特定于平台的故障转换。 - John Saunders

0

如果 Web 服务将公开使用,网络安全红队会喜欢提供详细的错误消息,以便对基础设施进行询问。然后我们可以针对该服务器使用特定的漏洞利用。(这并不是好事)。您的代码将在问题注册表中出现。建议在公共 Web 服务中使用任何默认的.NET异常消息的人只是在建议主题的变化或禁用诊断能力。建议使用不透露攻击服务器方法的自定义异常文本。


0

您能再解释一下吗?Web服务的服务器端可能会抛出异常。Web服务的服务器端可以向客户端返回消息。该消息可能包含错误信息,而该错误信息可能特别包括异常详细信息。或者也可能不包括。在客户端,通常有一个生成的代理来处理来自服务器的消息。如果响应包含错误信息,则此代理可能会生成异常。

您想了解这个场景的哪个部分呢?


@Bruce: 未捕获的异常将被转化为故障。在某些情况下,这些故障将包括异常的详细信息。 - John Saunders
@Bruce:我了解Web服务的工作原理,但我的问题更多是关于架构设计方面的。有时候我确实需要抛出异常,在这种情况下堆栈跟踪信息会被序列化到客户端。我认为这不是一个好主意。有什么最好的方法来隐藏这些细节?或者返回一个“Return”对象(我举的例子是CampaignMonitors API示例)是否是答案? - Ryan Tomlinson
@Ryan:逐个处理web.config中customeError标签的所有组合。我相信其中一个可以关闭堆栈跟踪。 - John Saunders
@John:请看原问题的评论。很遗憾,这对我来说不是一个选项。 - Ryan Tomlinson

0

我认为抛出异常通常比返回结果更好的设计模式。

我认为在您的 Web 服务中所要做的是,通过将以下模式应用于每个公开为 Web 服务的方法来隐藏堆栈跟踪:

public void MyWebServiceMethod() {
try
{

 ///Do something that may cause an error

} catch(Exception ex)
{ throw new ApplicationException("User friendly descritption of exception");

}

}

或者你也可以

catch(Exception ex) { throw ex; }

如果重新抛出异常,将会隐藏原始堆栈跟踪信息,这可能会影响你的 Web 服务客户端。


@Bogdan:首先,微软在 .NET 1.1 中就已经弃用了 ApplicationException。请改用“Exception”。其次,我印象中 OP 不想要任何堆栈跟踪信息。 - John Saunders
1
@John,我所说的ApplicationException是指任何自定义异常。好的,比如说它应该是MyWebServiceException或类似的东西。而且实际上它并没有被弃用,像System.Threading.WaitHandleCannotBeOpenedException这样的异常仍然继承自它。微软只是说他们认为它不是非常有价值,但你使用什么作为你的异常基类自然是你自己的选择,有时也受当前项目中应遵守的编码规范所影响。 - Bogdan_Ch

0

我不明白为什么你不能两者兼顾?捕获异常,将其记录下来(可以记录到数据库或文件中),然后返回错误代码。这样,您就可以优雅地执行WebService调用,并通知错误,同时还有其他地方可以进一步调试。


@James:坚持使用标准可能更好。它提供了错误处理机制,为什么不使用呢?此外,开发人员有时会忘记检查错误代码。这就是为什么引入异常的原因,而SOAP Faults则是Web服务版本的异常处理机制。 - John Saunders
正如@John所说,我也同意,异常是用来通知错误的。异常将被序列化为SOAP故障。因此,返回错误代码并不适合协议。请参见下面的链接: http://msdn.microsoft.com/en-us/library/ds492xtk(VS.85).aspx - Ryan Tomlinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接