Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.NET Convert.To/FromBase64String导致SOAP消息中的OutOfMemory异常_.net_Web Services_Soap_Base64_Out Of Memory - Fatal编程技术网

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

.NET Convert.To/FromBase64String导致SOAP消息中的OutOfMemory异常,.net,web-services,soap,base64,out-of-memory,.net,Web Services,Soap,Base64,Out Of Memory,我使用SOAP扩展来加密/解密服务器和客户端Web服务之间的SOAP消息 一般流程是,在发送soap消息之前,1.提取消息正文,2.加密消息,3.向消息中添加客户端信息,4.将消息放回消息中,最后将修改后的soap消息发送到服务器 它的工作与小要求完美。 但在发送大请求时,当我试图将加密的字节数组转换为人类可读的字符串(Base64String),然后将其放回SOAP消息时,会引发OutOfMemory异常。 在调试器中,我可以看到消息太大,当在Stackoverflow上查找该异常时,我知道C

我使用SOAP扩展来加密/解密服务器和客户端Web服务之间的SOAP消息

一般流程是,在发送soap消息之前,1.提取消息正文,2.加密消息,3.向消息中添加客户端信息,4.将消息放回消息中,最后将修改后的soap消息发送到服务器

它的工作与小要求完美。 但在发送大请求时,当我试图将加密的字节数组转换为人类可读的字符串(Base64String),然后将其放回SOAP消息时,会引发OutOfMemory异常。 在调试器中,我可以看到消息太大,当在Stackoverflow上查找该异常时,我知道
Convert.ToBase64String(bytearr)
在转换整个大字节数组时将抛出OOM异常,我应该逐块转换

但当我更改为逐块转换这个字节数组时,仍然会出现OOM异常,如下代码所示

请给我一些处理这个问题的建议

SOAP消息修改方法:

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
其他信息

异常堆栈跟踪:

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
Length):2748763210

加密(
bytearr
Length)后:54975280

添加(a)第二个OOM的堆栈跟踪和(b)正在处理的
bytearr
的长度。另外,尝试预先分配一个内存流,其容量刚好足以容纳base64编码的消息。默认情况下,MemoryStream在需要扩展时会将其容量加倍,我猜这就是它爆炸的地方。@AntonTykhyy:我已经添加了一些关于消息长度和异常堆栈跟踪的附加信息。我还用预测的大小初始化了
MemoryStream
。看起来OOM不会出现在Convert.ToBase64String上,因为我们已经在流中完成了。但当我试图从流中获取整个字符串以推回XML SOAP消息时,OOM仍然发生。堆栈跟踪与注释“still THROW OOM”的行不匹配。是哪一个?顺便说一下,您不需要使用内存流和所有这些读写器。只需创建一个字符串生成器并直接向其追加base64块。另外,我觉得奇怪的是,一个2,7G字符长的字符串加密到54M字节(缓冲区的大小是多少?)可能是一个整数。长于int.MaxValue元素的数组需要使用长索引,并且并非所有CLR代码都一致地使用长索引。