问题
I have a ASP.NET 3.5 page which has a repeater containing lines of information and custom buttons to change their status.
Suppose it's like this
btn1 btn2 btn3 Id Title Description Status1 Status2
btn1 and btn2 are used to change the status1 and 2 respectively.
btn3 redirects to a custom handler which sends back a downloadable MS-Word report. This happens without actually leaving the page.
The repeater is inside an updatePanel so I can update the statuses without having to reload the entire page everytime.
When I click btn1 or 2, the loading spinner appears as usual, and fades out when the process is completed and the status is changed.
When I click btn3, the loading spinner stays there, never going out, even after I finish my download.
What could be happening ?
Handler code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.IO;
using PublishVersionControlCore;
using System.Configuration;
namespace PublishVersionControlWebControl.Handler
{
public class WordFileHandler : IHttpAsyncHandler
{
private HttpContext _context;
private AsyncTaskDelegate del;
protected delegate void AsyncTaskDelegate(HttpContext context);
#region IHttpAsyncHandler Members
public WordFileHandler()
{
this.del = new AsyncTaskDelegate(ProcessRequest);
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
// Store context
_context = context;
return del.BeginInvoke(context, cb, extraData);
}
public void EndProcessRequest(IAsyncResult result)
{
this.del.EndInvoke(result);
}
#endregion
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
HttpResponse resp = context.Response;
resp.Clear();
int workItemId = 0;
if (Int32.TryParse(context.Request.QueryString["wi"], out workItemId))
{
MemoryStream ms = null;
using (WorkItemReportService.ReportClient client = new WorkItemReportService.ReportClient())
{
byte[] resultFile = client.GenerateWorkReport(
new Uri(ConfigurationManager.AppSettings["serverUri"]),
workItemId,
ConfigurationManager.AppSettings["wordTemplate"]);
ms = new MemoryStream(resultFile);
}
resp.ContentType = "application/octet-stream";
resp.AddHeader("content-disposition", String.Format("attachment;filename=RelatorioSimples_WI-{0}.docx", workItemId));
resp.Buffer = true;
ms.WriteTo(resp.OutputStream);
resp.End();
}
}
#endregion
}
}
ItemCommand in the repeater:
if (e.CommandName.Equals("WordExport"))
{
string uri = HttpContext.Current.Request.RawUrl;
string url = string.Format("{0}/WordReport.dohx?wi={1}",
uri.Substring(0, uri.LastIndexOf("/")), wivdata.SystemID);
Response.Redirect(url);
}
Aspx Page (I pasted it all since I didn't figure out what was relevant and what wasn't):
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="~/ListaDeAtividadesPage.aspx.cs"
MasterPageFile="~/_layouts/customapplication.master" Inherits="PublishVersionControlWebControl.ListaDeAtividadesPage, PublishVersionControlWebControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=78508f22b73cda2b" %>
<%@ Register Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
Namespace="System.Web.UI" TagPrefix="asp" %>
<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<link rel='stylesheet' text='text/css' href='/_layouts/Extensions/Versioning/css/style.css' />
<script src="/_layouts/Extensions/Versioning/js/jquery.tools.min.js" type="text/javascript"></script>
<script src="/_layouts/Extensions/Versioning/js/jquery.corner.js" type="text/javascript"></script>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderPageImage" runat="server">
<img width="145" height="54" alt="Dashboard" src="/_layouts/Microsoft.TeamFoundation/images/notes.png" />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea"
runat="server">
<asp:Literal ID="TitleContent" runat="server"></asp:Literal>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<script type="text/javascript">
_spOriginalFormAction = document.forms[0].action;
_spSuppressFormOnSubmitWrapper = true;
</script>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="updPanel">
<ProgressTemplate >
<div class="follower">
<asp:Image ID="imgUpdate" CssClass="follower" ImageUrl="/_layouts/Extensions/Versioning/img/ui/ajax-loader.gif"
runat="server" />
<span class="follower">Carregando...</span>
</div>
</ProgressTemplate>
</asp:UpdateProgress>
<div>
<asp:UpdatePanel ID="updPanel" runat="server">
<ContentTemplate>
<asp:Literal ID="tooltipScript" runat="server" />
<div class="buttonBar">
<hr style="color: #426DA8;" />
<asp:Button CssClass="specific" ID="btnUpdateWI" Text="Atualiza WIs da Lista" runat="server"
UseSubmitBehavior="false" />
<asp:Button CssClass="specific" ID="btnRelatorioScripts" Text="Relatório de Scripts / ZIPs"
runat="server" />
<asp:Button CssClass="specific" ID="Button1" Text="Relatório de Publicações" runat="server" />
<asp:Button CssClass="generic" ID="btnVolta" Text="Volta ao Menu de Versões" runat="server" />
<hr style="color: #426DA8;" />
</div>
<asp:Repeater ID="rptListaAtividades" runat="server">
<HeaderTemplate>
<asp:Label ID="comentarioHeader" runat="server"/>
<h3>
<b class="rollback">Rollback</b> | <b class="emteste">Em Teste</b> | <b class="aindanaoincluido">
Ainda não Incluído</b> | <b class="parcialmenteok">Atividade Parcialmente OK</b>
| <b class="todosok">Atividade OK em Todas as Lojas</b> | <b class="parcpublicado">Parcialmente Publicada</b> | <b class="publicado">Atividade
Publicada</b>
</h3>
</HeaderTemplate>
<ItemTemplate>
<div class="item" style="display: inline-block; font-size: 12px">
<asp:ImageButton ToolTip="Gerar Relatório Word" ImageUrl="/_layouts/Extensions/Versioning/img/wordexport.png"
CommandName="WordExport" ID="btnWordExport" CssClass="itembutton" runat="server" />
<asp:ImageButton ToolTip="Marcar como Rollback" ImageUrl="/_layouts/Extensions/Versioning/img/rollback.png"
CommandName="MarkAsRollback" ID="btnItemRollback" CssClass="itembutton" runat="server" />
<asp:ImageButton ToolTip="Esta atividade possui código. Clique para sinalizar como apenas procedure/config"
ImageUrl="/_layouts/Extensions/Versioning/img/code.png" CommandName="MarkAsProc"
ID="btnItemProc" CssClass="itembutton" runat="server" />
<asp:Image ToolTip="Esta atividade não possui scripts de banco/zips." ImageUrl="/_layouts/Extensions/Versioning/img/noscript.png"
runat="server" CssClass="itembutton" ID="btnItemScript" />
<asp:Label ID="labelWI" Text="" runat="server"></asp:Label>
<asp:Literal ID="tooltip" runat="server" />
<asp:Label ID="labelState" Text="" runat="server"></asp:Label>
<span style="color: #4A82CB">
<%# DataBinder.Eval(Container.DataItem, "SystemAssignedTo") %>
- </span><span style="color: Navy">
<%# DataBinder.Eval(Container.DataItem, "SystemTitle") %>
</span>
<asp:HiddenField ID="workItemID" runat="server" />
</div>
<hr class="item" noshade style="color: #4CBDCB; height: 2px; background-color: #4CBDCB" />
</ItemTemplate>
</asp:Repeater>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</asp:Content>
Other details:
- It's a layouts page in WSS 3.0
- I'm not sure the update panel is where it should be
回答1:
You can not call the Response.Redirect(url)
from call inside of an updatepanel.
With this redirect you break the viewstate, and you never return the informations that updatepanel ask. Find some other way for your download link, or remove updatepanel.
Understand how ajax and UpdatePanel work. You send an ajax request, and UpdatePanel wait for the answer data, and you never send it to him, so the indicator still wait for ever. But after you have made a post you break the viewstate, and on your second post you going to have javascript errors.
Some possible solution is to render a javascript after the postback to make the redirect but with javascript function call.
来源:https://stackoverflow.com/questions/9062813/aspupdateprogress-never-goes-away-after-clicking-on-downloadable-content-inside