Sunday, April 3, 2011

Best way to return dynamic non-html content from a page

I should start by saying that I am using ASP.NET using C# in a .NET 2.0 environment. In particular, I am trying to generate a csv download when the user clicks on a link button. The link to my postback is inside an UpdatePanel. In the past (before ajax) to return non-html content I would use code such as the following:

string filename = e.CommandArgument.ToString();//somefile.csv
string fileContents = SomeClass.GetFile(filename);

Response.AddHeader("Content-disposition", 
                   string.Format("attachment; filename={0}", filename));
Response.Write(fileContents);

But since the content is not trying to do a full refresh of the browser this technique does not work.

Does someone have a better approach for this kind of situation. One constraint I have is that I am stuck with .net 2.0 for this part of the project and can't switch to 3.5 to solve this problem.

p.s. I need to generate the content with a dynamic filename as well

From stackoverflow
  • I would avoid generating a postback for this at all. Istead, you want to use a completely separate page, preferably even just a handler (*.ashx). Then you can use a normal hyperlink and your old attachment code will work just fine.

    minty : This is helpful but I need to generate a dynamic filename as well. any hints on that?
    Joel Coehoorn : You'd pass it to the new handler via the query string. If need be you update the hyperlink on each partial postback in the update panel to point to the correct url.
    configurator : I'd say this is the right thing to do. Simply redirect to a different page in the LinkButton's event handler using Response.Redirect("new url");
  • Create a server-side container (even an HTML DIV with runat="server") inside the UpdatePanel, and set the .InnerHtml or .InnerText property to the fileContents variable when the UpdatePanel is refreshed.

    minty : So you are suggesting just poping the csv content into a div?
  • This is some anonymized code I'm using to generate a CSV download from an multi dimensional array.

    Response.Clear();
    Response.ClearHeaders();
    Response.ContentType = "application/vnd.ms-excel";
    String shippingFileName = "filename.csv";
    Response.AddHeader( "Content-Disposition", "attachment; filename=" + shippingFileName );
    String[] row = { "Head1", "Head2" .... };
    Response.Write( arrayToCSVString( row ) ); // quotes commas, and other formatting niceties
    
    foreach (row in arrayOfRows) Response.Write( arrayToCSVString( row ) );
    Response.Flush();
    
  • I think the answer is to make sure that LinkButton performs a synchronous operation. I think Joel's answer is better, but something like this should work for post backs.

    Make sure the UpdatePanel's UpdateMode is set to "Conditional" and add a trigger to the Update Panel

    <asp:UpdatePanel ... UpdateMode="Conditional">
        <ContentTemplate>...</ContentTemplate>
        <Triggers>
            <asp:PostBackTrigger ControlID="CsvLinkButton" />
        </Triggers>
    </asp:UpdatePanel>
    

0 comments:

Post a Comment