简体   繁体   中英

asp.net viewstate errors - “Invalid length for a Base-64 char array or string.” and “The input is not a valid Base-64 string”

My .Net application is recording some errors that I have tracked to the viewstate. I've read quite a bit on this, and found some information that simply hasn't helped me to get to the root of the problem. The errors are:

  • Invalid length for a Base-64 char array or string.
  • The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

These errors happen somewhat infrequently, and often to the same small subset of users. Often, simply redirecting the user to the same page again does not result in the same error

In an attempt to resolve these errors, I implemented two different solutions. In each solution, I attempted a string replace for blank spaces as well as attempted to ensure that the viewstate string was an appropriate length by appending "=" characters. Additionally, in one test I compressed the viewstate as well. Code for each of those attempts is below.

Compressed Viewstate

Public Class baseCompressor
    Inherits System.Web.UI.Page
    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
        Dim viewState As String = Request.Form("__VSTATE")
        viewState = viewState.Replace(" ", "+")

        Dim mod4 As Integer = viewState.Length Mod 4
        If mod4 > 0 Then
            viewState += New String("=", 4 - mod4)
        End If
        Dim bytes As Byte() = Convert.FromBase64String(viewState)
        bytes = compressor.Decompress(bytes)
        Dim formatter As New LosFormatter()
        Return formatter.Deserialize(Convert.ToBase64String(bytes))
    End Function

    Protected Overrides Sub SavePageStateToPersistenceMedium(viewState As Object)
        Dim formatter As New LosFormatter()
        Dim writer As New StringWriter()
        formatter.Serialize(writer, viewState)
        Dim viewStateString As String = writer.ToString()
        Dim bytes As Byte() = Convert.FromBase64String(viewStateString)
        bytes = compressor.Compress(bytes)
        ScriptManager.RegisterHiddenField(Me, "__VSTATE", Convert.ToBase64String(bytes))
    End Sub

End Class

Public NotInheritable Class compressor
    Private Sub New()
    End Sub

    Public Shared Function Compress(data As Byte()) As Byte()
        Using output As New MemoryStream()
            Using gzip As New GZipStream(output, CompressionMode.Compress, True)
                gzip.Write(data, 0, data.Length)
                gzip.Close()
                Return output.ToArray()
            End Using
        End Using
    End Function

    Public Shared Function Decompress(data As Byte()) As Byte()
        Using input As New MemoryStream()
            input.Write(data, 0, data.Length)
            input.Position = 0
            Using gzip As New GZipStream(input, CompressionMode.Decompress, True)
                Dim output As New MemoryStream()
                Dim buff As Byte() = New Byte(4096) {}
                Dim read As Integer = -1
                read = gzip.Read(buff, 0, buff.Length)
                While read > 0
                    output.Write(buff, 0, read)
                    read = gzip.Read(buff, 0, buff.Length)
                End While
                gzip.Close()
                Return output.ToArray()
            End Using
        End Using
    End Function
End Class

Uncompressed Viewstate

Public Class baseNonCompressor
    Inherits System.Web.UI.Page
    Protected Overrides Sub SavePageStateToPersistenceMedium(viewState As Object)
        Dim formatter As New LosFormatter()
        Dim writer As New StringWriter()
        formatter.Serialize(writer, viewState)
        Dim viewStateString As String = writer.ToString()
        Dim bytes As Byte() = Convert.FromBase64String(viewStateString)
        ScriptManager.RegisterHiddenField(Me, "__VSTATE", Convert.ToBase64String(bytes))
    End Sub

    Protected Overrides Function LoadPageStateFromPersistenceMedium() As Object
        Dim viewState As String = Request.Form("__VSTATE")
        viewState = viewState.Replace(" ", "+")

        Dim mod4 As Integer = viewState.Length Mod 4
        If mod4 > 0 Then
            viewState += New String("=", 4 - mod4)
        End If
        Dim bytes As Byte() = Convert.FromBase64String(viewState)
        Dim formatter As New LosFormatter()
        Return formatter.Deserialize(Convert.ToBase64String(bytes))
    End Function
End Class

The results have still left me with the original two errors as well as a new error:

  • Unable to read beyond the end of the stream.

The new error occurs on the Deserialize call. Can anyone point me to what the problem might be? While my code is in VB, C# solutions are also welcomed.

First you should take the Base64 string and be sure it is valid. There are many online tools.

These might be wrong:

Dim mod4 As Integer = viewState.Length Mod 4
If mod4 > 0 Then
    viewState += New String("=", 4 - mod4)
End If

From your code I sense you already know why. It's just wondering if it really behaves well in all cases, for example you shouldn't pad with four ==== if the modulo is 0.

Second, consider if this goes through a GET . The HTTP protocol has hard limits on the status line's maximum length.

In other words: if you set it as a parameter in the URL's query string, and the data is big (next to 1K) I'd recommend strongly to prefer a POST instead of a GET .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM