问题 Web服务是否应该抛出异常或结果对象


我不确定在Web服务中抛出异常是一个好主意我感到非常高兴。如果不是堆栈跟踪,我也不会介意。这不是我不想要的。

我已经围绕几个实现进行了研究,似乎对此没有达成共识。例如,CampaignMonitor会返回Result对象,而其他人则不会。

在架构上,我不确定返回一个返回对象是否有意义,当然异常是一个例外,但我对Return对象的喜好是对最终用户来说它是一个更优雅的解决方案。

有没有人有更好的解决方案?

编辑

BTW我正在使用ASMX Web服务,其中打开CustomErrors不是一个选项。


12377
2018-06-19 17:35


起源

实际上,我相信删除异常细节的方法是使用web.config中的customErrors标记。信不信由你。 - John Saunders
@John:是的,这就是我在这里说的。不幸的是,这不是我的选择。否则对我来说这将是一个更简单的问题:(。 - Ryan Tomlinson


答案:


您在谈论什么堆栈跟踪?你试过这个吗?

在ASMX和WCF服务中,未捕获的异常将转换为SOAP Fault。在这两种情况下,它们都可以配置为不包含任何堆栈跟踪。实际上,这是WCF中的默认值。

因此,返回这样的错误的正确方法是通过错误。产生错误的一种方法是抛出而不处理异常。


6
2018-06-19 17:39



本质上,我想通知用户的是一个带有错误代码和desciption(我选择的)的异常。我觉得Web服务和应用程序架构的异常处理之间存在语义上的差异,但我不确定是否应该区别对待它们。当出现故障时,您不会在代码中返回Result对象。 Web服务应该是不同的。不(你暗示)。我想我的问题是如何抽象异常细节? - Ryan Tomlinson
阅读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


不要让你在Web服务中的事实混淆了这个问题。这只是一个实现细节。

使用您的正常异常处理策略。最佳实践说不要在低级代码中捕获异常 - 除非您可以在那里解决该异常并继续正常进行。应该将异常提升到表示层,以便可以通知用户错误。

因此,应用于Web服务 - 通常抛出异常(导致SoapFault)。这允许调用客户端代码使用它的内置异常处理标准来处理它。


8
2018-06-19 17:50



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


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

如果出现业务错误,请返回包含错误说明的响应对象;如果系统错误,抛出异常。


2
2018-06-19 17:52



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


你能澄清一下吗? Web服务的服务器端可以抛出异常。 Web服务的服务器端可以向客户端返回消息。该消息可能包含错误信息,并且该错误信息可能具体包括异常详细信息。或者它可能不会。在客户端,您通常有一个生成的代理来处理来自服务器的消息。如果该响应包含错误信息,则此代理可能会生成异常。

您想知道这个场景的哪个部分?


0
2018-06-19 17:40



@Bruce:未捕获的异常将被转换为错误。在严峻的情况下,这些将包括除了细节。 - John Saunders
@Bruce:我理解Web服务是如何工作的,我的意思是更多的架构设计。有些情况下我确实需要抛出异常。在这些情况下,堆栈跟踪信息被序列化到客户端。我不认为这是个好主意。隐藏细节的最佳方法是什么?或者是返回“返回”对象的答案(我给出的示例是CampaignMonitors api示例)。 - Ryan Tomlinson
@Ryan:处理web.config中的customeError标记的所有组合。我相信其中一个会关闭堆栈跟踪。 - John Saunders
@John:请参阅原始问题的评论。不幸的是,我不是一个选择。 - Ryan Tomlinson


我认为抛出异常通常是一种更好的设计模式,然后返回结果。 我想您必须做的是在Web服务中隐藏堆栈跟踪,方法是将以下模式应用于作为Web服务公开的每个方法:

public void MyWebServiceMethod()   {
尝试
    {

 ///Do something that may cause an error

} catch(Exception ex)
     {         抛出新的ApplicationException(“用户友好   异常的解释“);

}

}

或者你也可以

catch(Exception ex){       抛出前}

如果重新抛出异常,则将从Web服务的客户端隐藏原始堆栈跟踪。


0
2018-06-19 17:46



@Bogdan:首先,MS已经在.NET 1.1中弃用了ApplicationException。请改用“例外”。其次,我的印象是OP根本不需要堆栈跟踪。 - John Saunders
@John,通过ApplicationException我的意思是任何自定义异常。好的,我们可以说它应该是MyWebServiceException或类似的东西。另外,事实上它并没有被弃用,而System.Threading.WaitHandleCannotBeOpenedException等异常仍然继承自此。 MS只是告诉他们不认为它是非常有价值的,但你用作异常的基类仍然是你自己的选择,有时候你应该遵守当前项目中应该遵守的编码约定。 - Bogdan_Ch


我不明白为什么你不能两者兼顾?捕获异常,将其记录(记录到数据库或文件),然后返回错误代码。通过这种方式,您可以正常执行webservice调用,并且还可以通知错误,并且您可以在其他位置进行进一步调试。


0
2018-06-19 18:25



@James:坚持标准可能会更好。它提供了故障,为什么不使用它们呢?此外,开发人员忘记检查错误代码。这就是发明异常的原因,SOAP Faults是异常的Web服务版本。 - John Saunders
正如@John所说,我同意,有例外可以告知错误。异常将序列化为SOAP错误。因此,返回错误代码不能很好地适应协议。见下文: msdn.microsoft.com/en-us/library/ds492xtk(VS.85).aspx - Ryan Tomlinson