I've created a page that allows users to download a file when they click a button... the button's onclick event is linked to the following chunk of code:
this.Page.Response.Clear();
this.Page.Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Zip;
this.Page.Response.AppendHeader("C开发者_运维百科ontent-Disposition", "attachment; filename=\"" + System.IO.Path.GetFileName(filename) + "\"");
this.Page.Response.TransmitFile(filename);
this.Page.Response.Flush();
this.Page.Response.End();
The download works fine, but now when I try to interact with the page, (for instance, hit the download button again), nothing posts back.
Am I responding to the download request incorrectly (should I be using a different/new response object), or is there something else I need to do to make the page active after the download?
Edit:
So I've tried encorporating the two posters suggestions for creating a httphandler, and calling a Response.Redirect to the handler from the button's click event.
void submitButton_Click(object sender, EventArgs e)
{
label.Text = "Boo!";
this.Page.Response.Redirect("~/ViewAttachment.ashx?id=foo", false);
}
If I step through this on the debugger, it continues after the redirect call, but the page just returns to a state where the button doesn't work, and the labels have their default values. Am I now doing the redirect wrong?
If using another handler an option?
Here's a slimmed down version of what I've used before (suggestions welcome this was a quick write). The HttpHandler (AttachmentFile is just a class with the blob data and some attributes collected when the file was uploaded):
public class AttachmentHandler : IHttpHandler
{
public const string QueryKeyID = "ID";
public void ProcessRequest(HttpContext context)
{
var r = context.Response;
var attachmentID = context.Request.QueryString[QueryKeyID];
Attachment a = DataContext.GetById<AttachmentFile>(attachmentID);
r.ContentType = a.ContentType;
r.AppendHeader("Content-Type", a.ContentType);
r.AppendHeader("content-disposition", string.Format("attachment; filename=\"{0}{1}\"", a.AttachmentName, GetExtension(a.FileName)));
r.BufferOutput = false; //Stream the content to the client, no need to cache entire streams in memory...
r.BinaryWrite(a.BlobData);
r.End();
}
private static string GetExtension(string fileName)
{
if(fileName.IsNullOrEmpty()) return string.Empty;
var i = fileName.LastIndexOf(".");
return i > 0 ? fileName.Substring(i) : string.Empty;
}
}
In the web.config
:
<system.web>
<httpHandlers>
<add verb="*" path="ViewAttachment.ashx" type="MyNamespace.AttachmentHandler, MyWebDllName"/>
</httpHandlers>
</system.web>
Then all you do is render a link in the form of ~/ViewAttachment.ashx?ID=5
on the page, clicking the button will download the file, but not mess with your page's lifecycle at all.
Now there are more considerations, like security and such....I trimmed them out for this example. I'm also using this style of link: ~/Attachment/{id}
via webforms routing...if either of these interest you I'll update to include them. Or you could hate this approach all-together...just letting you know it's an option.
You are mostly there.
All you need to do in your button click event handler is Response.Redirect to another ASPX page. Put that code your wrote on the other page.
Then everything will work just as you expect. The browser will actually stay on the original page and not go to the new page because you have set the content disposition to attachment - which is great.
By using Response.Clear() you've killed the headers. While there may appear to be valid html markup in the browser there really isn't. The headers are gone, so the controls that appear to be still rendered aren't valid. If you click "back" you should be able to repost information. What you probably want to do is make this call in a different window using PostBackUrl in your button click and setting the target of your form to a different window (then using SetTimeout to reset it to _self).
精彩评论