woensdag 23 maart 2011

Alternative to saving a file in Silverlight

In Silverlight the most common way of saving a file is done by opening a SaveFileDialog and then using the provided stream to write the file to the filesystem.
Although this is a preferred method it does provide some problems in the current release of Silverlight:
  • ·        First of all, there is no download added in the download history of your browser.  So once the user has saved the file, he or she needs to remember where the file was saved and under what name it was saved.
  • ·        Another issue is that there is no support for entering a default filename in the current release of Silverlight (SL4 at the time of writing).  Without a doubt that Microsoft will fix this in the next release, but as the deadline of current project approaches, we want to have this functionality now.
A possible solution to this problem is navigating to a download page in your Silverlight application.  The download page will send a response to the user.  In this response we will fill the content header with the requested file.  In the provided example, I temporarly buffer the file.  The reason I do this is so I can delete the file from the filesystem.  One scenario where you wish to do this, is when preparing downloads and moving them to a temporary location.  Enough talk, here is the code:
In the Silverlight application we navigate to the download location, we add a parameter to tell the page which file and where it is:
HtmlPage.Window.Navigate(new Uri(String.Format("download.aspx?File={0}", someFileName)), "_blank");

Then in the codebehind of the download page we can add following code:
protected void Page_Load(object sender, System.EventArgs e)
{
    // Get the filepaths
    string filePath = ConfigurationManager.AppSettings(DownloadRootPathSetting);
    string fileLocation = Request.QueryString("File");
    System.IO.FileInfo TargetFile = new System.IO.FileInfo(Path.Combine(filePath, fileLocation));

    // Buffer the file
    byte[] buffer = new byte[TargetFile.Length + 1];
    FileStream sr = TargetFile.OpenRead();
    using ((sr))
    {
        sr.Read(buffer, 0, buffer.Length);
    }

    // Assemble the response
    Response.Clear();
    Response.AddHeader("Content-Disposition", "attachment; filename=" + TargetFile.Name);
    Response.AddHeader("Content-Length", TargetFile.Length.ToString());
    Response.ContentType = "application/octet-stream";
    Response.BinaryWrite(buffer);

    // Delete the file
    File.Delete(Path.Combine(filePath, fileLocation));
    Directory.Delete(Path.GetDirectoryName(Path.Combine(filePath, fileLocation)));

    // Send the response back
    Response.End();
}

Enjoy!

1 opmerking: