异常处理 SOAP 扩展





4.00/5 (7投票s)
2005年6月6日
3分钟阅读

99344

2029
SOAP 扩展用于将完整的异常信息从服务器传输到客户端。
引言
我在公司里的主要项目涉及一个相当大的应用程序,它使用 Windows Forms 作为前端,并通过 Web 服务与服务器上的业务逻辑和数据访问代码进行通信。我发现很难追踪服务器端未处理异常的原因,因为在 SOAP 消息中返回的异常信息有限,所以我创建了一个 SOAP 扩展来提供更多信息。
工作原理
这是一个相当简单的代码,SOAP 扩展会监听在两台机器之间传递的每条消息。如果在即将发送回客户端的响应中检测到异常,该扩展会注意到这一点,并获取有关异常的完整信息,然后将其插入到返回客户端的 XML 流中。
客户端在接收到 SOAP 响应后,会注意到流中存在异常,并且该扩展会再次介入,以检索我们在服务器上插入到流中的附加信息。一旦获得这些信息,它会抛出一个包含该扩展信息的新异常。
ProcessMessage
方法是任何 SOAP 扩展的核心,它会在服务器和客户端上为请求和响应进行(反)序列化之前和之后被调用。它的工作是在正确的点在输入和输出流之间复制信息,并可以选择介入并检查或操作 SOAP 消息。我们对它的实现如下
Public Overrides Sub ProcessMessage( _
ByVal message As System.Web.Services.Protocols.SoapMessage)
Select Case message.Stage
Case SoapMessageStage.BeforeSerialize
'Do nothing
Case SoapMessageStage.AfterSerialize
'If exception present in message, write details
'to the new stream
If Not message.Exception Is Nothing Then
InsertExceptionDetails(message.Exception)
End If
'Copy new stream to old stream
newStream.Position = 0
StreamCopy(newStream, oldStream)
Case SoapMessageStage.BeforeDeserialize
'Copy old stream to new stream
StreamCopy(oldStream, newStream)
newStream.Position = 0
Case SoapMessageStage.AfterDeserialize
'If exception present in message,
'get details from stream and throw to caller
If Not message.Exception Is Nothing Then
Dim DetailString As String
DetailString = GetExceptionDetails()
Throw New Exception(DetailString)
End If
Case Else
Throw New ArgumentException("Invalid message stage")
End Select
End Sub
这个类中的其他重要方法被称为 InsertExceptionDetails
和 GetExceptionDetails
。它们负责将扩展的异常信息插入到流中并检索它。扩展的信息被插入到标准的 soap:Fault
元素中的一个名为 ExtendedExceptionDetails
的 XML 元素中。
InsertExceptionDetails
实现
''' <summary>
''' Insert details of the specified exception
''' into the output stream
''' </summary>
''' <param name="ex">Exception to write details for</param>
Private Sub InsertExceptionDetails(ByVal ex As Exception)
'Read output stream into XML document
newStream.Position = 0
Dim Reader As New XmlTextReader(newStream)
Dim MessageDoc As New XmlDocument
MessageDoc.Load(Reader)
Dim NsMgr As New XmlNamespaceManager(MessageDoc.NameTable)
NsMgr.AddNamespace("soap", _
"http://schemas.xmlsoap.org/soap/envelope/")
'Construct string describing exception
Dim ErrorInfo As String
ErrorInfo = ex.ToString()
'Find existing soap:Fault node describing exception
Dim ExceptionNode As XmlNode
ExceptionNode = MessageDoc.SelectSingleNode( _
"//soap:Fault", NsMgr)
'Add extended exception detail node to Fault node
Dim ExceptionDetail As XmlElement
ExceptionDetail = MessageDoc.CreateElement( _
"ExtendedExceptionDetails")
ExceptionDetail.InnerText = ErrorInfo
ExceptionNode.AppendChild(ExceptionDetail)
'Write XML document back to output stream
newStream = New MemoryStream
MessageDoc.Save(newStream)
End Sub
GetExceptionDetails
实现
''' <summary>
''' Reads extra exception information from stream and
''' returns it as a string
''' </summary>
''' <returns>Details of any exception detail found in
''' the input stream</returns>
Private Function GetExceptionDetails() As String
'Read input stream into XML document
newStream.Position = 0
Dim Reader As New XmlTextReader(newStream)
Dim MessageDoc As New XmlDocument
MessageDoc.Load(Reader)
Dim NsMgr As New XmlNamespaceManager(MessageDoc.NameTable)
NsMgr.AddNamespace("soap", _
"http://schemas.xmlsoap.org/soap/envelope/")
'Find extended exception detail node
Dim ExceptionDetailNode As XmlNode
ExceptionDetailNode = MessageDoc.SelectSingleNode( _
"//soap:Fault/ExtendedExceptionDetails", NsMgr)
'Return detail text if found, empty string otherwise
If Not ExceptionDetailNode Is Nothing Then
Return ExceptionDetailNode.InnerText
Else
Return ""
End If
End Function
使用代码
要使用该代码,请在客户端和 Web 服务项目中添加对 ExceptionHandlingSoapExtension
程序集的引用。 将以下部分添加到客户端上的App.Config 和服务器上的Web.Config 中
<webServices>
<soapExtensionTypes>
<add
group="0"
priority="1"
type="ExceptionHandlingSoapExtension.
ExceptionManagementSoapExtension,
ExceptionHandlingSoapExtension"
/>
</soapExtensionTypes>
</webServices>
此代码指示客户端和服务器上的 ASP.NET 使用此 SOAP 扩展来处理消息。
配置好 SOAP 扩展后,每次在执行 Web 方法期间发生异常时,都会在客户端上抛出一个异常,该异常的消息字段将填充完整的堆栈跟踪,显示服务器上发生的情况。
屏幕截图显示了从 Web 方法异常返回的标准信息。
屏幕截图显示了由 SOAP 扩展提供的扩展信息。
真实世界的用法
安全
像这样设置公开可访问的 Web 服务会存在很大的安全风险; 暴露有关 Web 服务内部运作的信息可能对恶意用户非常有用,而完整的堆栈跟踪会暴露很多! 我们将此扩展与各种加密和身份验证系统结合使用,并且 Web 服务不会在公共互联网上公开访问,因此几乎没有此信息落入坏人之手的危险。
跨平台用法
我认为使用此扩展的非 .NET 客户端将简单地忽略额外的异常信息,但我不能保证这一点。 在我的例子中,我们创建的 Web 服务永远不会被我们开发的客户端以外的客户端访问,所以我没有对此进行调查。
结论
我认为对于我正在开发的应用程序类型来说,Web 服务是否是正确的选择是值得商榷的,但在我开始从事该项目之前就做出了选择。
对我来说,学习如何编写 SOAP 扩展很有趣,我发现 MSDN 文档有点误导,但它们肯定是操作 Web 服务消息的简单而强大的方法。
我希望这篇文章对某人有帮助,我欢迎任何反馈 - 我知道我还有很多东西要学!
历史
- 06/06/2005: 创建。