Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Trick to download dynamic files from a SharePoint WebPart

4.67/5 (2 votes)
17 Jul 2013CPOL3 min read 16.5K  
Create files at runtime and download from a SharePoint WebPart.

Introduction

Many times a developer needs to create files dynamically in the WebPart background code and download them at user request. However, a Response.End() statement in WebPart does not work as expected and allows download only once or not at all. This article/tip gives simple steps to achieve dynamic / "on the fly" / at runtime construction of files and allow download through web part multiple times.

Background

I was developing a web part where images are to be displayed in thumbnail format and information related to those images is to be downloaded if user clicks the image. The image URL and description was stored in a SharePoint list. 

I began with reading SPList items one by one and to save the list read operation on user click, I kept the image description in a hidden DIV (.infoDiv in code below) near the image (.image in code below) tag. Added a __doPostBack using jQuery in the image click  function registered through jQuery. 

Using the code 

JavaScript
$(".image").click(function(){
    var info = $(".image").next(".infoDiv").html();
    $("#<%=infoHidden.ClientID %>").val(info);
    __doPostBack('IMGInfoSent','');
});

The above code snippet was passing the image information through an ASP.NET hidden field viz. infoHidden. When the __doPostBack is received in Page Load event, the __EVENTTARGET information is read from the Request object and file was created using the information in the hidden field and written back to the Response object using code below: 

Please note, the content in infoHidden field were encoded in base64 format to avoid any HTML encoding issues due to content itself. 

C#
if (Page.IsPostBack)
{
    if (Request["__EVENTTARGET"] != null)
    {
        if (Request["__EVENTTARGET"] == "IMGInfoSent")
        {
            byte[] bytes = Convert.FromBase64String(infoHidden.Value);
            string normalString = Encoding.Default.GetString(bytes);
            byte[] fileContent = Encoding.Default.GetBytes(normalString);
            infoHidden.Value = string.Empty;                            
            Response.Clear();
            Response.ClearHeaders();
            Response.ClearContent();
            Response.Buffer = true;
            Response.AddHeader("Content-Disposition", 
              "attachment;filename=myfile.txt");
            Response.ContentType = "text/plain";
            Response.BinaryWrite(fileContent);
            Response.End();
            return;
        }
    }
}

The C# code above was decoding the base64 value from the hidden variable and writing to a text file. 

This solution was working well till user clicks an image once. For the first time user clicks on an image and the download starts, however, for second time if user click on another or same image nothing was happening. During debug and later on Google I found that the issue is the Response variable modifications done for file download. The Response.End() and Response Header modifications are blocking the SharePoint web part to allow download once again and even it stopped the __doPostBack call from second request onward.

Then suddenly I remembered that we earlier created a download helper file to address another such issue where we wanted the SharePoint to forcefully download a PDF instead of opening it in the browser window. And decided to apply similar solution to my problem and write an article over here. 

So....Here is the solution...

  1. Right click on the project solution in Visual Studio 2010 or above. (I Assume your web part is under same solution.)
  2. Add new Application Page in the solution. It will create a folder tree like below:
  3. Layouts --> <Folder with your Project Name> --> An ASPX page. 

  4. Add following code in the Page Load method of this ASPX page.
  5. C#
    if (Request["fn"] != null && Request["fd"] != null)
    {
        string fileName = Request["fn"] == string.Empty ? "ImageInfo" : Request["fn"];
        string fileData = Request["fd"];
    
        byte[] bytes = Convert.FromBase64String(fileData);
        string normalString = Encoding.Default.GetString(bytes);
        byte[] fileContent = Encoding.Default.GetBytes(normalString);
    
        Response.Clear();
        Response.ClearHeaders();
        Response.ClearContent();
        Response.Buffer = true;
        Response.AddHeader("Content-Disposition", 
          "attachment;filename=" + fileName +".txt");
        Response.ContentType = "text/plain";
        Response.BinaryWrite(fileContent);
        Response.End();
    }

    The fn and fd are query string parameters to share file name and file data with the application page. 

  6. Added an anchor tag outside the image thumbnail and assigned href attribute value as in code below (in the web part):
  7. C#
    href = "/_layouts/<Folder with your Project Name>/<Name of your application page>.aspx?fn="+
      Server.UrlEncode(myFileName)+"&fd="+Server.UrlEncode(fileData); 

Thus, the anchor tag has passed file name and file data to the application page and in the Page Load the application page will initiate the file download process.

Now, irrespective of how many times user click on an image, file will be downloaded each time by creating "on the fly" every time. The query string parameters will pass file name and file data in base64 format to the application page each time. 

Hope this helps someone......or......myself in future.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)