问题
I'm using SOAP Extensions to encrypt/decrypt SOAP messages between server and client consume WebService.
General flow is, before sending soap message, 1.Extract message's body, 2.Encrypt it, 3.Append client info to it, 4.Put it back to message, and finally send modified soap message to server.
It work perfectly with small request.
But when sending large request, an OutOfMemory Exception is thrown when I tried to transform encrypted byte array to human readable string (Base64String) before put it back to SOAP message.
In debugger I could see that message is too large, and when looked for that exception on Stackoverflow, I've known that Convert.ToBase64String(bytearr)
will throw OOM Exception when convert whole large bytes array, and I should convert chunk by chunk.
But I still get OOM Exception when I change to convert chunk by chunk of this bytes array as below code
Please give me some advices to dealing with this problem.
SOAP Message modified method:
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
And below is encryption method:
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
ADDITIONAL INFO
Exception 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()
Message Length:
Before Encrypt (p_strInput
Length): 2748763210
After Encrypt (bytearr
Length): 54975280
来源:https://stackoverflow.com/questions/26227757/net-convert-to-frombase64string-cause-outofmemory-exception-in-soap-message