Download de arquivo com UpdatePanel    

Olá pessoal!

Agora, vou fazer um post bem rápido sobre um erro que ocorre quando é tentado realizar download em uma página com UpdatePanel.

Não é um post para detalhar o uso de UpdatePanel, isso você pode ver aqui, mas apenas um de seus comportamentos.

É um post simples, apenas para responder um pergunta: Não é possível fazer download com UpdatePanel? A resposta é: Sim, é possível. Veremos como logo abaixo.

Tomando como base o post sobre exportar para Excel, vou acrescentar a funcionalidade Ajax a ele um pouco diferente do que fiz no post de UpdatePanel.

Como explicado no post anterior, o UpdatePanel só deve estar na região que deve ser atualizada, e com certeza um arquivo para ser baixado não deve estar na região de atualização.

Vamos ao código!

Veja o código abaixo, extraído do post de UpdatePanel:

   1: <asp:ScriptManager ID="mng" runat="server"></asp:ScriptManager>
   2: <h2>Exportando para Excel</h2>
   3: <p>Nome:<asp:TextBox ID="txtNome" runat="server"></asp:TextBox></p>
   4: <p>Idade:<asp:TextBox ID="txtIdade" runat="server"></asp:TextBox></p>
   5: <p>Email:<asp:TextBox ID="txtEmail" runat="server"></asp:TextBox></p>
   6: <p><asp:Button Text="Salvar" runat="server" ID="btnSalvar" OnClick="btnSalvar_Click" /></p>
   7: <asp:UpdatePanel runat="server" >
   8:     <ContentTemplate>
   9:         <asp:GridView ID="grid" runat="server" AllowPaging="true" PageSize="5" AutoGenerateColumns="true"
  10:             OnPageIndexChanging="grid_PageIndexChanging">
  11:         </asp:GridView>
  12:     </ContentTemplate>
  13:     <Triggers>
  14:         <asp:AsyncPostBackTrigger ControlID="btnSalvar"  EventName="Click"/>
  15:     </Triggers>
  16: </asp:UpdatePanel>
  17: <asp:Button ID="btnExportar" Text="Exportar" runat="server" OnClick="btnExportar_Click" />

Apesar dessa página estar utilizando UpdatePanel, o Download do botão btnExportar vai funcionar. Por que? Por que a ação dele não é assíncrona. Ele não é Trigger de nenhum UpdatePanel.

Veja bem, quando tentamos baixar um arquivo dentro de um UpdatePanel, o conteúdo retornado para o Browser não é um HTML válido, logo, não será possível adicioná-lo dentro do UpdatePanel e o Asp.Net/ JavaScript reclama.

Se utilizarmos o botão Exportar dentro do UpdatePanel, teremos um erro, veja a seguir:

   1: <asp:UpdatePanel runat="server" >
   2:     <ContentTemplate>
   3:         <asp:GridView ID="grid" runat="server" AllowPaging="true" PageSize="5" AutoGenerateColumns="true"
   4:             OnPageIndexChanging="grid_PageIndexChanging">
   5:         </asp:GridView>
   6:         <asp:Button ID="btnExportar" Text="Exportar" runat="server" OnClick="btnExportar_Click" />
   7:     </ContentTemplate>
   8:     <Triggers>
   9:         <asp:AsyncPostBackTrigger ControlID="btnSalvar"  EventName="Click"/>
  10:     </Triggers>
  11: </asp:UpdatePanel>

Agora, na linha 6, o meu botão está dentro do UpdatePanel, e como ao clicar nele o Asp.Net Ajax vai preparar tudo para fazer Assíncrono, ao ter o retorno inválido (um Excel, por exemplo, não é um retorno válido) vai gerar o erro, que pode variar de acordo com a versão do Framework utilizado.

Mas então só botões que estão fora de um UpdatePanel podem fazer download? Lógico que não! Se você tiver o botão em uma GridView, que deve estar dentro de um UpdatePanel, e ele deve realizar um download, como fazer? Ou por qualquer motivo o seu botão tem que estar dentro do UpdatePanel? Simples, coloque o evento do botão, ou da Grid, como um Trigger Síncrono. Veja:

   1: <asp:UpdatePanel runat="server" >
   2:     <ContentTemplate>
   3:         <asp:GridView ID="grid" runat="server" AllowPaging="true" PageSize="5" AutoGenerateColumns="true"
   4:             OnPageIndexChanging="grid_PageIndexChanging">
   5:         </asp:GridView>
   6:         <asp:Button ID="btnExportar" Text="Exportar" runat="server" OnClick="btnExportar_Click" />
   7:     </ContentTemplate>
   8:     <Triggers>
   9:         <asp:AsyncPostBackTrigger ControlID="btnSalvar"  EventName="Click"/>
  10:         <asp:PostBackTrigger ControlID="btnExportar" />
  11:     </Triggers>
  12: </asp:UpdatePanel>

Agora meu botão, que está dentro do UpdatePanel, vai consegui realizar o Download, porque na linha 10 eu o adicionei como um Trigger de PostBack normal (Síncrono).

Caso eu não faça isso, terei o seguinte erro (Asp.Net 4):

Erro em tempo de execução do Microsoft JScript: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed.

A mensagem pode mudar, como disse, de acordo com o FrameWork utilizado. Poderia ser:

Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.

Como disse no post sobre UpdatePanel, não existe mágica. Internamente o Framework Ajax da Microsoft utilizar os objetos Ajax do Browser (XMLHttpRequest), assim como o Jquery faz, e através desses objetos não é possível realizar download. Você poderia transferir os bytes de um arquivo de forma assíncrona, mas não seria possível convertê-lo em arquivo, porquê o JavaScript, em geral, não tem permissão no Browser para realizar esse tipo de função (acessar IO, memória, etc). caso contrário seria muito fácil fazer vírus.

Bom, espero que ajude quem precise dessa ajuda.

Até o próximo.

20. julho 2011 21:09 by Frederico B. Emídio | Comments (10) | Permalink

Comments

Caio Ferreiro - Totvs
Parabéns pelo seu post, me ajudou muito e funcionou perfeitamente.
Obrigado!
09/08/2011 20:25:10 #
Dionísio Carvalho
Muito obrigado pela ajuda!
Excelente explicação.
10/02/2012 03:13:27 #
Wescley
No meu caso funcionou perfeitamente, mas preciso mostrar um update Progress para o usuário saber que está sendo executado a função de exportação do excel que demora bastante por ser uma quantidade considerável.

Alguma sugestão?
12/03/2012 08:42:17 #
Olá Wescley.

Nesse caso você deve controlar o progresso da geração do excel deparadamente da lógica do Download. Para controlar o progresso da geração você pode utilizar uma função Ajax simples que verifique alguma variável no servidor. Após receber dessa variável que a criação está pronta, você pode iniciar o processo de Download.

Att,
Frederico
12/03/2012 22:29:22 #
Poxa, cara valeu pela dica, me ajudou.

Abraços.
28/04/2012 21:09:48 #
Gabriel
Muito obrigado,

Essa dica me salvou aqui

Abraços.
12/07/2012 03:53:28 #
Legal Grabriel!

Continue visitando o site, em breve vou voltar a publicar.
Abs,
Fred
20/08/2012 07:34:57 #
Bianca Borges
Muito bom!
Obrigada, me salvou também Smile
10/11/2012 03:24:25 #
Muito bom

Muito obrigado...
11/02/2013 23:30:35 #
Muito bom o post, funcionou corretamente...

Eu estava realizando apenas um download e não funcionava, agora está beleza.
03/07/2014 17:34:10 #
Comments are closed

Sobre mim

Minha Imagem

Meu nome é Frederico Batista Emídio, trabalho com desenvolvimento de sistemas profissionalmente a oito anos, porém, já faço sites pessoais a pelo menos dez anos.

Para saber mais clique aqui.

Páginas

Calendário

<<  novembro 2018  >>
seteququsedo
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

Visualizar posts em um Calendário
Sigua @fredemidio

MCP Asp.NET