locked
response.end and download file problem using asp.net code inside sharepoint

    Question

  •  

    The download works the first time it is clicked but after I download the file and click "download" again event doesn't fire again. page completely loses scope after the download dialog pops-up. Once I download the first file and click any of the download buttons or other asp.net buttons it simply does nothing. I can browse away and back to the page and it works again.Refreshing page works but page freezes once download is done.

     

    Problem might be because of response.end but not sure how to fix.works fine in standard asp.net application.

    Thursday, March 20, 2008 1:49 PM

Answers

  • 5 minutes ago I stumbled across a solution that actually works in MOSS as well as in a pure ASP page. I came up with the solution after stepping through the page code with Firebug and as it's based on JavaScript I'd rate it as "not suitable for the faint of the heart".

    The hack is based on the fact that Sharepoint updates some kind of timestamp hash on the form before it is actually submitted to the server. This is done in order to prevent the form from being submit more than once if the user clicks before the Postback is completed, which is a good thing - except when trying to do what we are trying to do here. My idea was to remove that update code from the page, and as this code was called from the form's "onsubmit" handler, the approach was rather simple... Have a look:

    Code Snippet

    exportButton = new Button();
    exportButton.Text = "Generate some Excel stuff";

    // the handler method generates the file, writes it to the response and ends the response.
    exportButton.Click += onExcelExportClicked;

    // erase the form's onsubmit handler when the button is clicked
    exportButton.OnClientClick = "this.form.onsubmit = function() {return true;}";


    Believe it or not - this actually works. It's rather crude at this point, though - I guess I will write a more sophisticated replacement handler for the onsubmit that returns "true" once and reinstates the original handler. For now this will have to do, though.
    Thursday, April 10, 2008 1:31 PM
  • Try this:

    add this javascript:

    <script language="javascript" type="text/javascript">

    function myFunction()
    {

    window.WebForm_OnSubmit = function()
                          {return true;};
    }

    </script>


    and in code:

      protected void Page_Load(object sender, EventArgs e)
        {      
           ImageButton.OnClientClick = "myFunction()";             // or any other event
        }
    • Proposed as answer by Markus I_ Tuesday, May 04, 2010 1:29 PM
    • Marked as answer by Mike Walsh FIN Friday, December 24, 2010 4:47 PM
    Thursday, January 14, 2010 8:40 AM
  •  Response.Redirect didnt quite work, I used Response.End to save the  xml file on the page and ultimately close it.

     

    Raj
    Saturday, March 22, 2008 5:24 AM

All replies

  • put some sample code here from your code so we can see what needs to be correct. Thanks

     

    Thursday, March 20, 2008 2:01 PM
  • file is the file to be downloaded

    if (file.Exists)

    {

    Response.Clear();

    Response.AppendHeader("Content-Disposition", "attachment; filename=" + file.Name);

    Response.AppendHeader("Content-Length", file.Length.ToString());

    Response.ContentType = "application/octet-stream";

    Response.WriteFile(file.FullName);

    Response.End();

    }

     

    After file opened/saved to local the page freezes.

     

     

    Thursday, March 20, 2008 2:10 PM
  • for download file functionality, use a seperate page and redirect from this point to new page and new page will host this code and from that page after download, send the redirect back to this page. this way page download works fine. do not use response.end here. i have done this by writing an empty aspx page which i placed in layouts folder and from my webpart i sent a response.redirect to the layout page which can be accessed like "/_layouts/yourapp/downloadpage.aspx?anyquerystring" and my aspx page had no html in it. it was blank and the download code i placed inside page load.
    Thursday, March 20, 2008 2:28 PM
  •  

    I was aware of this separate.I had to do in same page as per requirements since there will be a list of downloads and going to another page is cumbersome and again when they come back i have to maintain where they are.I am not sure how to do without using response.end.I tried response.flush and response.close but the problem is same.
    Thursday, March 20, 2008 3:57 PM
  • dont worry about coming back to the original page, 1st try to do the same in a seperate page and if i remember it correctly that it will work even if you dont add a response.redirect back to the original caller. because download page has no html in it so your page will stay the same. please try it once to see if you successfully download the file. in order to get the file object in a seperate page, you can pass the page url in a query string or httpruntimecache object and on the downloadfile page, create spweb object and do spWeb.getFile  method to get the file object and rest of the code will stay the same.

     

    Thursday, March 20, 2008 6:42 PM
  •  

    I have to do in same page similar to how sharepoint send to ->download works in sharepoint view all site content etc.

    They are also asp.net pages and do not use separate page.

     

     

    Thursday, March 20, 2008 9:02 PM
  • This is a Very frustrating issue. And is still unresolved. Page redirection has no effect. What happens is that once the headers are changed and the response is flushed, the page dies. No more script or code works, no postbacks, nada.

     

    I have been working to resolve this issue for some time to no avail. Any help would be highly appreciated.

    Friday, March 21, 2008 2:55 PM
  •  Response.Redirect didnt quite work, I used Response.End to save the  xml file on the page and ultimately close it.

     

    Raj
    Saturday, March 22, 2008 5:24 AM
  • I had the same problem and figured out the problem by reflecting the code SharePoint uses for it's own download.aspx page (Microsoft.SharePoint.ApplicationPages.Download) and the javascript (in core.js) that calls this page. The only difference between the SharePoint code and mine is that they use window.location instead of window.open to open up the download.aspx page. As soon as I changed my ajax javascript code to do the same, it started working. So I'm not sure if it's an Ajax problem or a SharePoint related issue.

     

    Let me know if this worked for any of you..

    Wednesday, March 26, 2008 2:38 PM
  • I have the same problem and I really can't use any of the methods proposed so far - the download has to happen from a web part and the data to be downloaded is generated dynamically so it would be a pain to implement some kind of mechanism where a temporary file is stored on the disc and delivered by some kind of resource handler.

    It would be great if someone came up with an idea. I simply can't believe that the problem is that exotic - generating some kind of file and downloading it seems to be quite a common task to me.

    What bugs me most is the fact that my web part works perfectly inside a normal ASP page. It only breaks in the described way as soon as I put it into a MOSS page.
    Thursday, April 10, 2008 12:08 PM
  • 5 minutes ago I stumbled across a solution that actually works in MOSS as well as in a pure ASP page. I came up with the solution after stepping through the page code with Firebug and as it's based on JavaScript I'd rate it as "not suitable for the faint of the heart".

    The hack is based on the fact that Sharepoint updates some kind of timestamp hash on the form before it is actually submitted to the server. This is done in order to prevent the form from being submit more than once if the user clicks before the Postback is completed, which is a good thing - except when trying to do what we are trying to do here. My idea was to remove that update code from the page, and as this code was called from the form's "onsubmit" handler, the approach was rather simple... Have a look:

    Code Snippet

    exportButton = new Button();
    exportButton.Text = "Generate some Excel stuff";

    // the handler method generates the file, writes it to the response and ends the response.
    exportButton.Click += onExcelExportClicked;

    // erase the form's onsubmit handler when the button is clicked
    exportButton.OnClientClick = "this.form.onsubmit = function() {return true;}";


    Believe it or not - this actually works. It's rather crude at this point, though - I guess I will write a more sophisticated replacement handler for the onsubmit that returns "true" once and reinstates the original handler. For now this will have to do, though.
    Thursday, April 10, 2008 1:31 PM
  • I had a similar problem with a download link which was part of a gridview inside a webpart in a WSS v3 site.  The grid had a column which contains the relative path to a jpg file, and could also contain the original filename (i.e. the name to display in the 'save as' dialog), which was appended to the filename with an asterisk as the delimiter.

     

    After reading this thread, I used the following technique to resolve the problem:

     

    1.  Create a new page to perform the download (e.g. 'companyName_download.aspx').

    2.  In the page load event, I put the following:

     

    Code Snippet

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

    Handles Me.Load

            Dim filenames As String() = _

    Request.QueryString("filename").ToString.Split("*"c)


            Dim originalFilename As String
            Dim diskFilename As String = filenames(0)
            diskFilename = _

    Server.MapPath("~/{virtualDirectoryContainingFiles}/" & diskFilename)


            If filenames.Length = 2 Then
                originalFilename = filenames(1)
            Else
                'We don't have the original name, have to use the disk name...
                originalFilename = diskFilename
            End If
            DownloadFile(diskFilename, originalFilename)

        End Sub

     

     

     

    3.  Added the 'DownloadFile' function referenced from page load:

     

    Code Snippet

        '''
        ''' Download a file to the user's browser
        '''
        ''' The name of the physical file to be downloaded
        ''' The default 'save as' filename the user will see

        ''' when the save dialog pops up in the browser

        '''
        Private Sub DownloadFile(ByVal diskFilename As String, _

    ByVal downloadFilename As String)

            Response.Clear()
            Response.ClearHeaders()
            Response.AddHeader("Content-Type", "image")
            Response.AddHeader("Content-Disposition", _

    "attachment;filename=" & downloadFilename)

            Response.WriteFile(diskFilename)
            Response.End()

        End Sub

     

     

    4.  In the gridview, created a hyperlinkfield column, and set the following:

    DataNavigateUrlFields="{the name of the column that contains the file's relative path, plus original path}"

    DataNavigateUrlFormatString="~/{pathToDownloadPage}/{downloadPageName}.aspx?filename={0}"

     

    This works fine from both a straight ASP.Net page, and from a usercontrol hosted as a webpart within a WSS site.  You obviously need to ensure that you ship your download page with the files that are installed as part of your SharePoint solution, and ensure that the relative path will still be correct.

     

    I hope that this helps someone else in the same situation.

    Saturday, May 10, 2008 5:16 PM
  • This worked like a charm for me.  Thanks!
    Wednesday, May 14, 2008 10:47 PM

  •    Task:   Webpart. User clicks link to a file, stored as byte[] on a SQL Server. File is send to user via a webservice. A common open/save dialog appears. Webpart remains fully functional (no server controls "freezing").

       My suggestion:

    Link to the file created as:

    ...
    protected override void CreateChildControls()
     {
              base.CreateChildControls();

    ...
    HyperLink filelink = new HyperLink();
    string url = Context.Request.Url.PathAndQuery + "&FileID=1";
    filelink.NavigateUrl = url;
    filelink.Target = "_blank";       //   .Target = "_self"; works as well
    filelink.Text = "File1";
    Controls.Add(filelink)

    ...

    }


    When user clicks a link a new window/new address is starting to download. The page with the webpart loaded. So we have to check, if the querystring has required parameter(s) (in this case, ["FileID"]).

    ...

    protected override void OnLoad(EventArgs e)
            {
               
                object ob = Context.Request.QueryString["FileID"];          

                if (ob != null)
                {
                    int FileID = 0;
                    if (Int32.TryParse(ob.ToString(), out FileID))
                    {
    if(FileID > 0) {
                        try
                        {
                            HttpResponse httpResponse = Context.Response;

                            WS = new MyWebService();   
        WS.Credentials = _credentials;                 
                           
                            byte[] fl = new byte[_FileSize];
                            fl = WS.GetFile(FileID);

                            httpResponse.ClearHeaders();
                            httpResponse.Clear();

                            httpResponse.ContentType = _ContentType;
                            httpResponse.AddHeader("Content-Transfer-Encoding", "binary");
                            httpResponse.AddHeader("Content-Disposition", "attachment;filename=\"" + _fileName + "\"");
                            httpResponse.AddHeader("Content-Length", fl.Length.ToString());

                            httpResponse.BinaryWrite(fl);

                            httpResponse.Flush();
                            httpResponse.End();

                           
                        } // try
                        catch
                        {
                            //
                        } // catch
    } // if
                    } // if
                } // if
                else
                {
                    base.OnLoad(e);
                }  // if         
            } // OnLoad()

    ...

    File is downloaded and initial page (and webpart) ramains fully functional. Security is on the webservice, so don't worry about sending  parameter(s) in the open querystring.

    Works as supposed on MS Server 2003 + WSS 3.0 SP1 + IE7.

    Wednesday, May 21, 2008 5:43 AM
  • Hello,

     

    I'm facing similar issue what bhaskar faced.

    Onclick of button in webpart it just open/save window appears as i need to response.end inorder to generate the output i added the code similarly, it works first time after that it will not at all work..

     

    It works well in ASP.net page for any number of clicks on same page , why it doesnt work on MOSS webparts.

    Very Strange.

     

    Anyone provide solution without adding another page to layouts folder will be much appreciated.

     

     

    -Soma

    Friday, July 18, 2008 9:05 AM
  • this hint is great, now downloading files workes also for me! Thanks a lot! dieter
    Dieter Wiesflecker
    Wednesday, August 13, 2008 11:43 AM
  • Hi Zapes,

            you are simply great, this client side event is working greatly. It made my demo to go smoothly....
    I dont know why i have to add but it worked greatly......thanks for your simple solution.

     // erase the form's onsubmit handler when the button is clicked
    exportButton.OnClientClick = "this.form.onsubmit = function() {return true;}";

    Thanks,
    Mukthesh.
    Thursday, August 21, 2008 11:09 AM
  • hi bhaskar reddy,
    did get the solution for this problem i got the same problem.
    if u fix it let know abt it you response is highly appericiable
    Monday, April 27, 2009 4:25 PM
  • I am facing same problem. My page hangs up after response.end(). Please let me know if anyone solved this problem,

    Thursday, June 04, 2009 7:03 AM
  • Hey Thanks.

    This code is really working!
    I put below code at .aspx page.
    OnClientClick = "this.form.onsubmit = function() {return true;}"


    Wednesday, July 01, 2009 11:11 AM
  • Hi Zappes,

    Really a good snippet working  for button and imagebutton but  any suggestions to make it work for link button.
    Your response will be appreciated.

    Thanks in advance
    Thursday, July 30, 2009 1:39 PM
  • Hi, My requirment is to export grid view to excel file. i have used the following code to export to excel. its exporting as expected for first time. But the buttons are not working for second time. I kept the code
     <asp:ImageButton ID="btnExport" runat="server" ImageUrl="/sites/ndsindia/style library/images/export_btn.gif"
                        Width="74px" OnClick="btnExport_Click"  OnClientClick = "this.form.onsubmit = function() {return true;}"/>
    for the exporting image button. But it still giving the same problem. Could you please assist me on this.It will be appreciated.

    The code to export to excel:

    HttpContext.Current.Response.Write(sw.ToString());
                            HttpContext.Current.Response.Flush();
                            HttpContext.Current.ApplicationInstance.CompleteRequest();

    Regards,
    Johny Yadav
    • Proposed as answer by Johny Yadav Wednesday, August 26, 2009 10:31 AM
    • Unproposed as answer by Mike Walsh FIN Friday, December 24, 2010 4:45 PM
    Wednesday, August 26, 2009 10:25 AM
  • Hi Johny,

    Did u get the answer for ur problem? i am facing the same problem.
    I want to get download dialogue in new aspx page. but my new aspx page gets closes itself when control comes to Response.End(0 or Response.Flush();

    Any idea?

    Thank You,
    Anirudh
    Friday, September 04, 2009 7:34 AM
  • If using a LinkButton instead of a Button substitute: exportButton.OnClientClick = "this.form.onsubmit = function() {return true;}";
    with: exportButton .OnClientClick = "document.getElementsByTagName(\'form\')[0].onsubmit = function() {return true;}";
    • Proposed as answer by Cyber J-P Tuesday, March 16, 2010 6:57 PM
    • Unproposed as answer by Mike Walsh FIN Friday, December 24, 2010 4:48 PM
    Wednesday, September 09, 2009 10:20 PM
  • Hi,

    I have grid view and inside i have link button where i can download a file using the link button.
    In asp.net everything is working fine.

    But when i do the same in sharepoint for first click download works fine.after that all the click events get disabled.
    I tried the above solution but did not get any result.

    I wrote my download functionality in on click event of my link button and i retrieve the file name based on link button then pass the same to my share point url site,

    Please send me a solution.Any help would be appreciated.


    Regards,
    Anil
    Friday, October 23, 2009 1:56 PM
  • Try this:

    add this javascript:

    <script language="javascript" type="text/javascript">

    function myFunction()
    {

    window.WebForm_OnSubmit = function()
                          {return true;};
    }

    </script>


    and in code:

      protected void Page_Load(object sender, EventArgs e)
        {      
           ImageButton.OnClientClick = "myFunction()";             // or any other event
        }
    • Proposed as answer by Markus I_ Tuesday, May 04, 2010 1:29 PM
    • Marked as answer by Mike Walsh FIN Friday, December 24, 2010 4:47 PM
    Thursday, January 14, 2010 8:40 AM
  • Hi Baskar,

    The Better way to fix this issue is to create a new page and provide the Download option at the page load.
    Send the required inputs from your page to the new page as querystring.

    Then on button click Open the New page using Javascript as below.

    Response.Write("<script>window.open('NewPage.aspx?filepath=" + filepath +"');<script>");

    But dont use Response.Redirect

    This works fine for me instead of working on someother workarounds.

    Let me know, if you have anyother solution this.
    “Changing the Face” can change nothing.But “Facing the Change” can change everything.
    Wednesday, March 10, 2010 9:39 AM
  • Hi Anil,

    I have the same problem.

    Does your problem have been resolved yet?

    Thanks,
    Kevin
    Wednesday, March 10, 2010 9:51 AM
  • To erikx12,

    Fine solution! Thanks!
    Friday, March 12, 2010 3:47 PM
  • Thanks Zappes!! :) Your solution worked for me :D
    Tuesday, April 20, 2010 7:18 PM
  • 5 minutes ago I stumbled across a solution .

    Thanks Zapees !!!. Worked like charm ..
    • Edited by Mike Walsh FIN Friday, December 24, 2010 4:46 PM Full quote uses up screen space unnecessarily, Don't use it.
    Thursday, April 29, 2010 10:03 AM
  • If using a LinkButton instead of a Button substitute: exportButton.OnClientClick = "this.form.onsubmit = function() {return true;}";
    with: exportButton .OnClientClick = "document.getElementsByTagName(\'form\')[0].onsubmit = function() {return true;}";

    In my case the form is named "aspnetForm", but you can find the name with the page source.
    I'm using a LinkButton and in the OnClientClick property I used "document.forms['aspnetForm'].onsubmit = function() {return true;}" and it worked.
    Tuesday, May 04, 2010 10:32 AM
  • Wow, thank you so much for this post. Very helpfull!!!
    Friday, July 30, 2010 2:05 PM
  • Hi erikx12,

    Thank you very much. Your solution is very helpful. This solution avoids creating of new page for download purpose.

     

    Regards,

    Sunil Shet

     

    Friday, December 24, 2010 4:04 PM