我使用SOAP Extensions在服务器和客户端之间加密/解密SOAP消息消耗WebService。
一般流程是,在发送soap消息之前,1。提取消息的正文,2。加密它,3。将客户端信息添加到它,4。将其重新发送到消息,最后发送修改后的soap消息给服务器
它与小请求完美配合。
但是当发送大量请求时,当我尝试将加密的字节数组转换为人类可读的字符串(Base64String),然后将其重新发送回SOAP消息时,会抛出OutOfMemory Exception。
在调试器中我可以看到消息太大,当在Stackoverflow上查找该异常时,我已经知道Convert.ToBase64String(bytearr)
在转换整个大字节数组时会抛出OOM异常,我应该按块转换块
但是当我将这个字节数组的块改为转换块时,我仍然会得到OOM异常,如下面的代码
请给我一些处理这个问题的建议。
SOAP Message修改方法:
Private Shared Function EncryptSoap(ByVal streamToEncrypt As Stream, ByVal clientInfo As String, ByVal encryptKey As String) As MemoryStream
streamToEncrypt.Position = 0
'read the soap stream into a xml doc
Dim reader As XmlTextReader = New XmlTextReader(streamToEncrypt)
Dim xmlDoc As XmlDocument = New XmlDocument()
xmlDoc.Load(reader)
'' Select soap body to encrypt
Dim targetNode As XmlNode = xmlDoc.SelectSingleNode(SOAPConstraints.c_strSOAP_BODY_STR, nsmgr)
'' Encrypt SOAP Body
Dim encryptedString As String = Utilities.Rfc2898Encrypt(targetNode.InnerXml, encryptKey)
' build soap body string = clientInfo + Encrypted Request
Dim strbld As StringBuilder = New StringBuilder(clientInfo, clientInfo.Length + encryptedString.Length)
strbld.Append(encryptedString)
'now save the encrypted xml doc to the returning stream
targetNode.InnerXml = strbld.ToString
'now save the encrypted xml doc to the returning stream
Dim ms As MemoryStream = New MemoryStream()
xmlDoc.Save(ms)
ms.Position = 0
Return ms
End Function
以下是加密方法:
Public Shared Function Rfc2898Encrypt(ByVal p_strInput As String, ByVal p_strEncryptKey As String) As String
Try
'' Encrypt Object initialization
Dim rijndael As New System.Security.Cryptography.RijndaelManaged()
Dim encrypter As System.Security.Cryptography.ICryptoTransform = rijndael.CreateEncryptor()
Dim buffer As Byte() = System.Text.Encoding.Unicode.GetBytes(p_strInput)
Dim bytearr As Byte() = encrypter.TransformFinalBlock(buffer, 0, buffer.Length)
'' Convert to human readable string (Base64String)
'' Convert all at one => THROW OUT OF MEM EXCEPTION
'Return Convert.ToBase64String(bytearr) ''
Dim chunkSize As Integer = 3 * 1024
'' Convert chunk by chunk
''**ADD** Init MemoryStream with predicted capacity
Using ms As New MemoryStream((bytearr.Length / 3 + 1) * 4)
Dim sw As New StreamWriter(ms)
Dim intConvertCount As Integer = bytearr.Length \ chunkSize
For idx As Integer = 0 To intConvertCount - 1
sw.Write(Convert.ToBase64String(bytearr, idx * chunkSize, chunkSize)) '' => STILL THROW OUT OF MEM EXCEPTION
sw.Flush()
Next
'' convert last block
sw.Write(Convert.ToBase64String(bytearr, intConvertCount * chunkSize, bytearr.Length - intConvertCount * chunkSize))
sw.Flush()
ms.Position = 0
Dim sr As New StreamReader(ms)
Return sr.ReadToEnd
End Using
Catch ex As Exception
Throw ex
End Try
Return String.Empty
End Function
附加信息
异常StackTrace:
System.String.GetStringForStringBuilder(String value, Int32 startIndex, Int32 length, Int32 capacity)
System.Text.StringBuilder.GetNewString(String currentString, Int32 requiredLength)
System.Text.StringBuilder.Append(Char[] value, Int32 startIndex, Int32 charCount)
System.IO.StreamReader.ReadToEnd()
消息长度:
加密前(p_strInput
长度):2748763210
加密后(bytearr
长度):54975280