我正在用C#在ASP.NET上构建一个Web应用程序。 在按钮上单击我显示加载图像,同时正在执行数据库查询。然后我动态创建一个Excel文件并将其发送到客户端,如下所示:
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=" + filename + ".xlsx");
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.Unicode;
HttpContext.Current.Response.BinaryWrite(p.GetAsByteArray());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
我收到对话框,加载图片就在那里。
我尝试在上面的代码之前调用一个javascript函数(使用ClientScript.RegisterStartupScript函数),它没有用。据我所知,所有javascript代码都是在所有代码隐藏执行后运行的,但在这种情况下,一旦将文件发送到客户端,它就不会执行。
我还尝试创建一个单独的线程,并删除那里的加载图像。我把断点跟踪它,线程中的代码确实执行,但图像仍然存在。
有没有人知道如何处理这个问题?谢谢!
答案 0 :(得分:3)
您只能在一个请求/响应周期中发送或传输1 mime类型。 (我在这方面的知识是值得商榷的。)
那就是说,你可以围绕这个设计一个黑客。在客户端上使用iframe“下载文件”。您可以将其src
指向执行相同操作的ashx文件。
您需要连接iframe的onload事件,以便您的网页知道下载已完成;这就是你可以执行逻辑的地方。
好吧,经过挖掘,我已经发现我的答案是半生不熟!
问题是iframe在下载后不会触发onload事件。如果src
指向的url实际导航到另一个页面,onload事件将触发iff。我想这是设计的。我今天学到了 !
那么解决方法是什么?!
幸运的是,您可以将cookie传输到客户端。在客户端上,您的网页必须继续轮询此cookie的存在。因此,一旦您的网页能够检测到cookie的存在,这意味着浏览器已完成下载请求。以下帖子对此进行了详细讨论:
我将向您展示一些与处理程序文件(模拟下载)和客户端(具有iframe完成工作)相关的代码。这应该给你的要点:
<强> WebForm1.aspx的:强>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApp.FileDownload.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>iFrame Download</title>
<script type="text/javascript" src="Scripts/jquery-2.1.0.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.cookie.js"></script>
<script type="text/javascript">
function foo() {
console.log('foo');
//execute post-download logic here
}
$(function () {
$('input').click(function () {
//make sure we get rid of the
//cookie before download
$.removeCookie('downloaded');
var intrvl = setTimeout(function () { //this function polls for the cookie through which we track that the file has indeed been downloaded
console.log('timer');
var value = $.cookie('downloaded');
if (value == 'true') {
clearTimeout(intrvl);
foo();
}
}, 1000);
//this initiates the download
$('iframe').attr({
'src': 'download.ashx?id=' + $('#tbxRandomNumber').val()
});
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="tbxRandomNumber" runat="server"></asp:TextBox>
<input type="button" value="Download" />
<iframe src="about:blank" style="display:none"></iframe>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Next Random Number" />
</div>
</form>
</body>
</html>
我已经使用jquery cookies plugin来帮助我处理Cookie。
<强> download.ashx:强>
using System;
using System.Web;
namespace WebApp.FileDownload
{
/// <summary>
/// Summary description for download
/// </summary>
public class download : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.SetCookie(new HttpCookie("downloaded","true")); //setting cookie in the response
string id = context.Request.QueryString["id"] == null ? "NULL" : context.Request.QueryString["id"];
string str = string.Format("Content with id {0} was generated at {1}", id, DateTime.Now.ToLongTimeString());
context.Response.AddHeader("Content-Disposition", "attachment; filename=test.txt");
context.Response.AddHeader("Content-Length", str.Length.ToString());
context.Response.Write(str);
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
答案 1 :(得分:1)
看起来你在这里有一些误解。您只有一个请求,以及来自服务器的一个响应。创建新线程只会在服务器上发生,并且不会创建其他响应。
当您发送Excel文件时,您正在使用:
HttpContext.Current.Response.Clear();
通过清除响应,您将丢失之前添加的JavaScript。它永远不会到达客户端。
如果处理相当简单(总是只需几秒钟),我只需将加载动画设置为运行几秒钟并通过在初始onclick事件上设置超时来停止。它并不完美,但它会给用户一些即时反馈。
如果处理过程需要很长时间或很长时间,那么动画更重要。您可以尝试在隐藏的<iframe>
中加载Excel文件,并附加onload
事件以删除加载动画。
您需要创建一个单独的页面来处理生成Excel文件,而不是在服务器端OnClick
处理程序中执行。但是,我似乎记得在onload
上对<iframe>
事件的支持可能与旧的IE版本不一致。
答案 2 :(得分:0)
在浏览器中加载页面时,javascript在客户端中运行。您可能有一个隐藏的文本框,在您活动结束时,您可以将值放入该文本框中:
txtHidden.Text = "Hola Mundo"
您必须检查页面加载时的值:
<script type="text/javascript">
$(document).ready(function(){
if($("#txtHidden").length > 0 && $("#txtHidden").val() != '')
{
alert($("#txtHidden").val());
}
});
</script>
您可以将其置于Web用户控件中。 另一种解决方案:
<div class='button' id='btnGenerateDownload' onClick='GenerateDownload(this)'>
Click here <div id='loadingImage' class='loadingImage'></div>
</div>
JQuery的:
function GenerateDownload(caller)
{
//add loading gif:
var $loagingGIF = $(caller).children('#loadingImage').eq(0);
$loagingGIF.addClass('loadingImage');
var fileGeneratorUrl = 'ghFileGenerator.ashx';
var downloadHandlerUrl = 'ghDownloadHandler.ashx';
$.post({data: "File1"}, function(response){
//remove gif
$loagingGIF.removeClass('loadingImage');
if(response != '') //file key
{
downloadHandlerUrl += '?key=' + response;
var $link = $("<a />").attr('href', downloadHandlerUrl).html('download');
$link.appendTo($(caller));
}
});
}
的CSS:
.loadingImage{background: transparent url(images/loading.gif);}
.ashx的:
string filekey = context.Current.Request.Form("key");