.NET Convert.To/FromBase64String cause OutOfMemory Exception in SOAP message

喜你入骨 提交于 2019-12-13 04:13:43

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!