O que está causando este “comprimento inválido para uma matriz de caracteres de Base-64”

91

Tenho muito pouco para continuar aqui. Não consigo reproduzir isso localmente, mas quando os usuários recebem o erro, recebo uma notificação automática de exceção por e-mail:

Invalid length for a Base-64 char array.

  at System.Convert.FromBase64String(String s)
  at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
  at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState)
  at System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState)
  at System.Web.UI.HiddenFieldPageStatePersister.Load()

Estou inclinado a pensar que há um problema com os dados atribuídos ao viewstate. Por exemplo:

List<int> SelectedActionIDList = GetSelectedActionIDList();
ViewState["_SelectedActionIDList"] = SelectedActionIDList;

É difícil adivinhar a origem do erro sem ser capaz de reproduzi-lo localmente.

Se alguém já teve alguma experiência com esse erro, eu gostaria muito de saber o que você descobriu.

Fino
fonte

Respostas:

36

Já vi esse erro causado pela combinação de viewstate de bom tamanho e dispositivos / firewalls de filtragem de conteúdo agressivos (especialmente ao lidar com instituições de ensino fundamental e médio).

Nós contornamos isso armazenando Viewstate no SQL Server. Antes de seguir esse caminho, eu recomendaria tentar limitar o uso do viewstate, não armazenando nada grande nele e desligando-o para todos os controles que não precisam dele.

Referências para armazenar ViewState no SQL Server:
MSDN - Visão geral do PageStatePersister
ASP Alliance - Método simples para armazenar viewstate no projeto de código do SQL Server
- Modelo de provedor ViewState

Jimmie R. Houts
fonte
Copiei o estado da página e colei no Word. Tinha mais de 86.000 caracteres. Isso parece demais.
Slim
Caramba, estou enfrentando o problema agora. Desativei o ViewState para todos os controles possíveis. Estou usando um controle Wizard com várias páginas e muito conteúdo. Algum conselho?
Mike Cole de
@Mike C., esse é um problema muito frustrante! Você pode quebrar o conteúdo de cada página do assistente em controles de usuário e carregar o conteúdo sob demanda (via ajax?). Claro, esta é apenas uma solução para aquela página, se você começar a experimentar o problema de forma consistente, você pode querer considerar o armazenamento de viewstate em seu banco de dados. Atualizei minha resposta com referências para armazenar viewstate no SQL Server.
Jimmie R. Houts
1
Outro problema que encontrei com mais de 86.000 caracteres de comprimento (na verdade, pode estar perto de 85 K, eu acho, assumindo caracteres de byte único) é que seu aplicativo .NET também pode começar a colocar strings de viewstate no heap de objeto grande que pode levar a heap fragmentação ao longo do tempo (e eventualmente OutOfMemoryException) se o pool de aplicativos não for reciclado.
nada é necessário
Eu tenho o mesmo problema, como resolver esse problema, esclareça-o.
Sajith,
84

Depois que urlDecode processa o texto, ele substitui todos os caracteres '+' por '' ... portanto, o erro. Você deve simplesmente chamar esta instrução para torná-la compatível com a base 64 novamente:

        sEncryptedString = sEncryptedString.Replace(' ', '+');
Jalal El-Shaer
fonte
Coisas boas. Obrigado. Eu estava chamando um serviço da Web ASP.NET de um aplicativo C ++ MFC e poderia ter ramificado em várias direções tentando resolver isso e depois de já ter passado algumas horas nisso. Você acabou de me poupar muito tempo.
nspire
3
É só acertar esse problema e como vc falou ficou em espaços, trocando por +consertou. Herói!
mattytommo
Alguém pode dar orientação sobre onde incluir este código? Estou lidando com esse problema com frequência, mas a partir do snippet de código, não consigo determinar onde implementar a correção.
dst3p
@ dst3p Use-o onde quer que você encontre o erro no pipeline de processamento. Verifique o rastreamento da pilha e veja qual método está causando o erro.
Jalal El-Shaer
21

Meu palpite é que algo está codificando ou decodificando com muita frequência - ou que você tem texto com várias linhas.

As strings de Base64 devem ter um comprimento múltiplo de 4 caracteres - cada 4 caracteres representa 3 bytes de dados de entrada. De alguma forma, os dados do estado de exibição transmitidos pelo ASP.NET estão corrompidos - o comprimento não é múltiplo de 4.

Você registra o agente do usuário quando isso ocorre? Eu me pergunto se é um navegador mal-comportado em algum lugar ... outra possibilidade é que haja um proxy fazendo coisas impertinentes. Da mesma forma, tente registrar o comprimento do conteúdo da solicitação, para que você possa ver se isso acontece apenas para solicitações grandes.

Jon Skeet
fonte
No meu caso, os navegadores são sempre Safari, seja na versão móvel ou desktop
cockypup
12

Experimente isto:

public string EncodeBase64(string data)
{
    string s = data.Trim().Replace(" ", "+");
    if (s.Length % 4 > 0)
        s = s.PadRight(s.Length + 4 - s.Length % 4, '=');
    return Encoding.UTF8.GetString(Convert.FromBase64String(s));
}
Petr Voborník
fonte
Este método ajudou a resolver o problema. Embora eu não tenha usado a codificação UTF8
Abhishek Shrivastava
10
int len = qs.Length % 4;
            if (len > 0) qs = qs.PadRight(qs.Length + (4 - len), '=');

onde qsestá qualquer string codificada em base64

Bhuvana
fonte
8

Como outros mencionaram, isso pode ser causado quando alguns firewalls e proxies impedem o acesso a páginas que contêm uma grande quantidade de dados ViewState.

ASP.NET 2.0 introduziu o mecanismo ViewState Chunking que divide o ViewState em pedaços gerenciáveis, permitindo que o ViewState passe pelo proxy / firewall sem problemas.

Para ativar esse recurso, basta adicionar a seguinte linha ao seu arquivo web.config.

<pages maxPageStateFieldLength="4000">

Isso não deve ser usado como uma alternativa para reduzir o tamanho do ViewState, mas pode ser um contra-ataque eficaz contra o erro "Comprimento inválido para uma matriz de caracteres de Base-64" resultante de proxies agressivos e semelhantes.

Taz Vermelho
fonte
isso pode ter algum efeito colateral?
MonsterMMORPG
Nenhum que eu já tenha observado, mais informações sobre viewstate
Red Taz
então qual é o seu comprimento ideal? eu o defini em 1024
MonsterMMORPG
1

Isso não é uma resposta, infelizmente. Depois de encontrar o erro intermitente por algum tempo e, finalmente, ficar irritado o suficiente para tentar consertá-lo, ainda não encontrei uma solução. Porém, determinei uma receita para reproduzir meu problema, que pode ajudar outras pessoas.

No meu caso, é APENAS um problema de localhost, na minha máquina de desenvolvimento que também tem o banco de dados do aplicativo. É um aplicativo .NET 2.0 que estou editando com o VS2005. A máquina Win7 de 64 bits também possui VS2008 e .NET 3.5 instalados.

Aqui está o que irá gerar o erro, em uma variedade de formulários:

  1. Carregue uma nova cópia do formulário.
  2. Insira alguns dados e / ou postback com qualquer um dos controles do formulário. Contanto que não haja nenhum atraso significativo, repita tudo o que quiser e nenhum erro ocorrerá.
  3. Espere um pouco (1 ou 2 minutos, talvez, não mais que 5) e tente outro postback.

Um ou dois minutos de atraso "esperando pelo host local" e depois "A conexão foi redefinida" pelo navegador e global.asaxos logs de trap de erro do aplicativo:

Application_Error event: Invalid length for a Base-64 char array.
Stack Trace:
     at System.Convert.FromBase64String(String s)
     at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
     at System.Web.UI.Util.DeserializeWithAssert(IStateFormatter formatter, String serializedState)
     at System.Web.UI.HiddenFieldPageStatePersister.Load()

Nesse caso, não é o SIZE do viewstate, mas algo a ver com o cache de página e / ou viewstate que parece estar me incomodando. Definir <pages>parâmetros enableEventValidation="false", e viewStateEncryption="Never"na Web.confignão alterar o comportamento. Nem definir o maxPageStateFieldLengthpara algo modesto.

fortboise
fonte
1

Dê uma olhada em seus HttpHandlers. Tenho notado alguns erros estranhos e completamente aleatórios nos últimos meses depois que implementei uma ferramenta de compressão (RadCompression da Telerik). Eu estava percebendo erros como:

  • System.Web.HttpException: Não é possível validar os dados.

  • System.Web.HttpException: O cliente desconectou .---> System.Web.UI.ViewStateException: viewstate inválido.

e

  • System.FormatException: comprimento inválido para uma matriz de caracteres de Base-64.

  • System.Web.HttpException: O cliente desconectou. ---> System.Web.UI.ViewStateException: viewstate inválido.

Eu escrevi sobre isso no meu blog.

Michael
fonte
Seu blog está fora do ar. Você tem outro link ou pode postar as informações relevantes? thx
mga911
0

Isso se deve a um estado de exibição enorme. No meu caso, tive sorte, pois não estava usando o estado de exibição. Acabei de adicionar enableviewstate="false"a tag do formulário e o estado de exibição passou de 35k para 100 caracteres

coderman
fonte
0

Durante o teste inicial para Membership.ValidateUser com um SqlMembershipProvider, eu uso um algoritmo hash (SHA1) combinado com um salt e, se eu alterasse o comprimento do salt para um comprimento não divisível por quatro, recebi este erro.

Não tentei nenhuma das correções acima, mas se o sal estiver sendo alterado, isso pode ajudar alguém a identificar isso como a origem desse erro específico.

John
fonte
0

Como disse Jon Skeet, a string deve ser múltipla de 4 bytes. Mas ainda estava recebendo o erro.

Pelo menos ele foi removido no modo de depuração. Coloque um ponto de interrupção e, em Convert.FromBase64String()seguida, percorra o código. Milagrosamente, o erro desapareceu para mim :) Ele provavelmente está relacionado aos estados de exibição e outros problemas semelhantes, conforme outros relataram.

Hammad Khan
fonte
0

Além da solução de @jalchr que me ajudou, descobri que, ao chamar ATL::Base64Encodede um aplicativo C ++ para codificar o conteúdo que você passa para um serviço da Web ASP.NET, você precisa de algo mais também. Além de

sEncryptedString = sEncryptedString.Replace(' ', '+'); 

da solução de @jalchr, você também precisa garantir que não use oATL_BASE64_FLAG_NOPAD sinalizador em ATL::Base64Encode:

 BOOL bEncoded = Base64Encode(lpBuffer,
                    nBufferSizeInBytes,
                    strBase64Encoded.GetBufferSetLength(base64Length),
                    &base64Length,ATL_BASE64_FLAG_NOCRLF/*|ATL_BASE64_FLAG_NOPAD*/);
nspire
fonte