Wednesday, October 20, 2010

Old school CSV without creating a temp file

I had a request to export a report out to Excel today, which is something I’ve done a bunch of times before but always by producing a temporary file.  I figured I’d try something different, find a way to give me the same functions without having to worry about permissions on the file system, or deleting the files afterwards.

It turned out to be very easy… use a TextStream that writes out  a HTML header so Explorer does all the hard work.

On the ASPX page…

On the click event for the export button we turn off the usual ASP.NET view state stuff and make a new header with the content type of "application/vnd.ms-excel", this tells IE to start Excel regardless of the details sent.  Another interesting thing to see here is the Response.End call, you’ll need this to prevent ASP.NET sending the page refresh information along with your data.

protected void ExportButton_Click(object sender, EventArgs e)
{
      this.EnableViewState = false;
        Response.Clear();
        Response.Buffer = true;
        Response.ContentType = "application/vnd.ms-excel";
        Response.AddHeader("Content-Disposition", "inline;filename=TeamExport.csv");
        team.ExportToExcel(Response.Output, true);
        Response.Charset = "";
        Response.End();
}

On the Business Object its a simple matter of building up an array of results, making sure to wrap them in “” for each field.  Then added this to the HTML TextStream …..

/// <summary>
/// Export Global Team lists to Excel
/// </summary>
/// <param name="httpStream">The HTTP stream.</param>
public void ExportToExcel(TextWriter httpStream)
{
     // find all associated applications
     IList<Application> applications =  (from application in Application.FindAllByProperty("GlobalTeam", Id)
             select application).ToList<Application>();

     foreach(Application app in applications)
     { 
         string[] dataArr = new string[]
             {
                 WriteableValue(app.Id),
                 WriteableValue(app.GlobalTeamName),
                 WriteableValue(app.Title),
                 WriteableValue(app.SupportManager),
                 WriteableValue(app.ProjectManager),
                 WriteableValue(app.StartDate.ToShortDateString()),
                 WriteableValue(app.EndDate.ToShortDateString())
             };
         httpStream.WriteLine(string.Join(",", dataArr));
     }
}

public static string WriteableValue(object o)
{
    if (o == null || o == null)
        return "";
    else
        return "\"" + o.ToString() + "\"";
}

Its good to rediscover something old, simple but yet works so well ….