Friday, July 2, 2010

SharePoint 2010 and Silverlight (Downloading a file with the client object model)

Technorati Tags: ,,

When I was doing SivlerLight 2 development and using SP2007, I was wishing for a cleaner way of downloading a file. It just seemed so browser like to stream a file via the response stream and force the browser to pop open two dialogs like below. I had worked so hard on making the Silverlight application not to look like a traditional browser based application, it just seemed to be a shame.

Well when I was doing Silverlight 4 and SP2010 development I came across the SilverLight System.Windows.Controls.SaveFileDialog class. This is just like using the Windows.Forms.FileDialog class of old days except for Silverlight. Very nice, because you just get the save file dialog  without all the extra windows, making it behave more like a desktop application.

 

So I needed some code to get a file from SharePoint and then prompt the user with the SaveFileDialog. Remember everything must be called asynchronously in Silverlight. The code below uses the Sivlerlight client object model File.OpenBinaryDirect along with an “in-line” anonymous delegate allowing the callback code to be executed in the same method. Works out very well.

       private void DownloadFile(string path)
       {
           string filterTemplate = "!@Ext Files (*.!@Ext) | *.!@Ext";
           SaveFileDialog dialog = new SaveFileDialog();
           dialog.DefaultExt = Path.GetExtension(path).Substring(1);
           dialog.Filter = filterTemplate.Replace("!@Ext", dialog.DefaultExt);

           bool? result = dialog.ShowDialog();

           if (result.HasValue && result == true)
           {
               this.Busy = true;
               Stream sourceStream = null;
               Uri fileUrl = new Uri(path);

               ClientContext clientContext =
                   new ClientContext(fileUrl.GetComponents(
                       UriComponents.SchemeAndServer,
                       UriFormat.UriEscaped));

               Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileUrl.AbsolutePath,
                   (object eventSender, OpenBinarySucceededEventArgs eventArgs) =>
                   {
                       if (eventArgs.Stream != null)
                           sourceStream = eventArgs.Stream;
                       Deployment.Current.Dispatcher.BeginInvoke(() =>
                       {
                           using (Stream destStream = dialog.OpenFile())
                           {
                               byte[] bytes = new byte[sourceStream.Length];

                               sourceStream.Read(bytes, 0, (int)sourceStream.Length);
                               destStream.Write(bytes, 0, bytes.Length);
                               destStream.Flush();

                           }
                           this.Busy = false;
                       });

                   }, null);             
           }

       }

3 comments:

Anonymous said...

Thank you very much Steve, you saved me a week of valuable time.

Dan said...

Hi! I am getting a System.NotSupportedException when I try to make this call. The OpenBinaryDirect() says it wants the server relative url, so that is what I pass it. I also tried sending in an absolute url, but same problem. Have you encountered any of these issues?

Anonymous said...

I am getting the same error Not Supported Exception

Post a Comment