我需要在将文件发送给用户下载后运行几种方法。发生的事情是,在我向用户发送文件后,响应中止,response.end()
之后我再也无法执行任何操作。
例如,这是我的示例代码:
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
Response.ContentType = "application/pdf";
byte[] a = System.Text.Encoding.UTF8.GetBytes("test");
Response.BinaryWrite(a);
Response.End();
StartNextMethod();
Response.Redirect(URL);
因此,在此示例中,StartNextMethod
和Response.Redirect
未执行。
我尝试的是使用以下代码创建了一个单独的处理程序(ashx):
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
context.Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
context.Response.ContentType = "application/pdf";
byte[] a = System.Text.Encoding.UTF8.GetBytes("test");
context.Response.BinaryWrite(a);
context.Response.End();
}
并将其称为:
Download d = new Download();
d.ProcessRequest(HttpContext.Current);
StartNextMethod();
Response.Redirect(URL);
但同样的错误发生了。我已经尝试用CompleteRequest替换Response.End,但它没有帮助。
我想问题是我正在使用HttpContext.Current但是应该使用单独的响应流。那是对的吗?我如何在一个单独的方法中一般地做到这一点(假设我希望我的处理程序接受数据和内容类型的字节数组,并且可以从单独的响应中下载。我真的不想使用单独的页面进行响应。
更新
我仍然没有找到一个好的解决方案。我想在用户下载文件后做一些操作,但不使用单独的页面来处理响应\请求。
答案 0 :(得分:7)
<强>更新强>
由于您没有说第二页,请改为执行此操作。在页面中添加一个部分,用于检查查询字符串参数(类似于fileid或path等...)。如果存在此值,则使用现有代码启动下载过程。如果此值不存在则会正常运行。
现在,当用户点击下载链接时,您执行回发(您已经在进行回复)。在这篇文章中,在页面上创建一个iFrame,并使用添加的查询字符串参数(mypage.aspx?id = 12664或?download = true,类似的东西)将iFrame的URL设置为您的页面URL。在创建iframe后,执行任何额外的数据库/等等......你也希望如此。
示例强>
- http://encosia.com/ajax-file-downloads-and-iframes/
上面链接的示例使用了iFrame和更新面板,就像您正在谈论的那样。
原帖
Response.Flush将允许您在将文件发送给用户后继续处理,或者只是不调用Response.End(您实际上也不需要)。
但是Daniel A. White是正确的,你发送文件后实际上无法从代码中重定向,如果你尝试,你会收到错误。但如果需要,您可以继续执行其他服务器端操作。
其他答案与普遍的共识一致,你不能在文件开始下载后重定向:https://stackoverflow.com/a/822732/328968(PHP,但相同的概念,因为它一般涉及HTTP)。或Directing to a new page after downloading a file。
答案 1 :(得分:5)
Response.End()抛出一个线程中止异常。它旨在结束您的回复。 之后没有代码将在该线程中处理。
End方法使Web服务器停止处理脚本并返回当前结果。不处理该文件的其余内容。
你想要实现的目标是什么?
如果您的目的是允许pdf下载然后将用户带到其他页面,那么一些小的javascript可以帮助您。
添加一个带有计时器的脚本,将location.href设置为重定向的分页。
答案 2 :(得分:1)
正如前面的答案所述 - 返回PDF文件意味着发送HTTP标头。之后您无法发送另一个标头,而Response.Redirect()只是意味着发送HTTP 302。
如果您不想拥有单独的页面,或者您不想使用AJAX,为什么不尝试:
<head>
<meta http-equiv="refresh" content="3; url=http://www.site.com/download.aspx?xxxx">
</head>
实际上,这将显示您想要向用户显示的所需页面,并将在3秒后使用下载PDF文件的URL刷新页面。
答案 3 :(得分:1)
如图所示File Download in ASP.NET and Tracking the Status of Success/Failure of Download或this question的答案,以块的形式下载文件。当文件的最后一个块已写入客户端时,您可以执行所需的代码。 (不必在最后,根据您的需要,可以介于两者之间。)
答案 4 :(得分:0)
用户点击WebForm1.aspx
上的下载按钮开始下载文件。然后,在文件下载完成后(由WebForm2.aspx
提供),用户将自动重定向。
WebForm1.aspx
<script type="text/javascript">
$(document).ready(function () {
$('#btnDL').click(function () {
$('body').append('<iframe src="WebForm2.aspx" style="display:none;"></iframe>');
return true;
});
});
</script>
<asp:Button runat="server" ID="btnDL" ClientIDMode="Static" Text="Download" OnClick="btnDL_Click" />
WebForm1.aspx.cs
protected void btnDL_Click(object sender, EventArgs e)
{
var sent = Session["sent"];
while (Session["sent"]==null)
{// not sure if this is a bad idea or what but my cpu is NOT going nuts
}
StartNextMethod();
Response.Redirect(URL);
}
WebForm2.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.AddHeader("content-disposition", "attachment; filename=test.pdf");
Response.ContentType = "application/pdf";
byte[] a = System.Text.Encoding.UTF8.GetBytes("test");
Response.BinaryWrite(a);
Session["sent"] = true;
}
Global.asax.cs
protected void Session_Start(object sender, EventArgs e)
{
Session["init"] = 0; // init and allocate session data storage
}
注意:请确保不要使用ashx(通用处理程序)来提供下载。出于某种原因,除非你实现this,否则ashx和aspx中的会话不会相互通信。
答案 5 :(得分:0)
只需删除context.Response.End();
,因为无论如何都要重定向......
这里的问题是有缺陷的......你为什么要结束回应?
获取PDF并显示其链接或使用META
刷新重定向到PDF的位置,或者您也可以显示链接或使用这两种技术的组合。
答案 6 :(得分:0)
我相信你的尝试是行不通的。
这就是我要做的事情:
这与许多文件下载站点使用的行为相同。唯一的问题是如果隐藏框架失败(javascript关闭)以执行请求,为什么许多相同的网站在自动请求失败时可以使用该链接。
缺点:文件清理。
答案 7 :(得分:0)
我推荐这个解决方案:
不要使用response.End();
声明此全局变量:bool isFileDownLoad;
就在你的(Response.BinaryWrite(a);)set ==&gt;之后isFileDownLoad = true;
覆盖您的渲染,如:
/// /// AEG:处理线程中止异常非常重要 /// /// override protected void Render(HtmlTextWriter w) { if(!isFileDownLoad)base.Render(w); }