Thursday, January 12, 2012

How to download a document with Save As Dialog in SharePoint 2010 programmatically

There are many posts which describe how to download a document with Save As Dialog in ASP.NET. I found a good article which was written by Rick Strahl. This can be easily achieved with just 4 lines of code as follows -

Response.ContentType = "application/ms-word";

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

Response.TransmitFile( Server.MapPath(relativeUrl) );

Response.End();

However, its a different ball game when it comes to SharePoint. As we all know documents uploaded to any document library are stored in the database and when we use the above code snippet we get the error that the url is not a valid path.

The crux lies in getting the file object from the SPListItem that we get from the ListItemCollection, and write the file as a binary stream in the Response. The following code should help you achieve this -

private void OpenDocument(SPListItem listItem)
        {
        SPFile file = listItem.File;
            using (MemoryStream ms = new MemoryStream(file.OpenBinary()))
            {
                Response.Clear();
                // Clear the content of the response
                Response.ClearContent();
                Response.ClearHeaders();

                // Buffer response so that page is sent after processing is complete.
                Response.BufferOutput = true;

                // Add the file name and attachment, which will force the open/cance/save dialog to show, to the header
                Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
               
                // Add the file size into the response header
                Response.AddHeader("Content-Length", file.Length.ToString());

                // Set the ContentType - octet stream helps handle all content types generically
                Response.ContentType = "application/octet-stream";

                ms.WriteTo(Response.OutputStream);

                Response.Flush();
                Response.Close();
            }
}

The above code handles all content types and we need not explicitly get the content type of the document.