.NET Convert.To/FromBase64String导致SOAP消息中的OutOfMemory异常

时间:2014-10-07 02:37:15

标签: .net web-services soap base64 out-of-memory

我使用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

0 个答案:

没有答案