How to download/upload files from/to SharePoint 2013 using CSOM?

I am developing a Win8 (WinRT, C#, XAML) client application (CSOM) that needs to download/upload files from/to SharePoint 2013.

How do I do the Download/Upload?


Solution 1:

Upload a file

Upload a file to a SharePoint site (including SharePoint Online) using File.SaveBinaryDirect Method:

using (var clientContext = new ClientContext(url))
{
     using (var fs = new FileStream(fileName, FileMode.Open))
     {
         var fi = new FileInfo(fileName);
         var list = clientContext.Web.Lists.GetByTitle(listTitle);
         clientContext.Load(list.RootFolder);
         clientContext.ExecuteQuery();
         var fileUrl = String.Format("{0}/{1}", list.RootFolder.ServerRelativeUrl, fi.Name);

         Microsoft.SharePoint.Client.File.SaveBinaryDirect(clientContext, fileUrl, fs, true);
     }
}

Download file

Download file from a SharePoint site (including SharePoint Online) using File.OpenBinaryDirect Method:

using (var clientContext = new ClientContext(url))
{

     var list = clientContext.Web.Lists.GetByTitle(listTitle);
     var listItem = list.GetItemById(listItemId);
     clientContext.Load(list);
     clientContext.Load(listItem, i => i.File);
     clientContext.ExecuteQuery();

     var fileRef = listItem.File.ServerRelativeUrl;
     var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
     var fileName = Path.Combine(filePath,(string)listItem.File.Name);
     using (var fileStream = System.IO.File.Create(fileName))
     {                  
          fileInfo.Stream.CopyTo(fileStream);
     }
}

Solution 2:

This article describes various options for accessing SharePoint content. You have a choice between REST and CSOM. I'd try CSOM if possible. File upload / download specifically is nicely described in this article.

Overall notes:

    //First construct client context, the object which will be responsible for
    //communication with SharePoint:
    var context = new ClientContext(@"http://site.absolute.url")

    //then get a hold of the list item you want to download, for example
    var list = context.Web.Lists.GetByTitle("Pipeline");
    var query = CamlQuery.CreateAllItemsQuery(10000);
    var result = list.GetItems(query);

    //note that data has not been loaded yet. In order to load the data
    //you need to tell SharePoint client what you want to download:

    context.Load(result, items=>items.Include(
        item => item["Title"],
        item => item["FileRef"]
    ));

    //now you get the data
    context.ExecuteQuery();

    //here you have list items, but not their content (files). To download file
    //you'll have to do something like this:

    var item = items.First();

    //get the URL of the file you want:
    var fileRef = item["FileRef"];

    //get the file contents:
    FileInformation fileInfo = File.OpenBinaryDirect(context, fileRef.ToString());

    using (var memory = new MemoryStream())
    {
          byte[] buffer = new byte[1024 * 64];
          int nread = 0;
          while ((nread = fileInfo.Stream.Read(buffer, 0, buffer.Length)) > 0)
          {
              memory.Write(buffer, 0, nread);
          }
          memory.Seek(0, SeekOrigin.Begin);
          // ... here you have the contents of your file in memory, 
          // do whatever you want
    }

Avoid working with the stream directly, read it into the memory first. Network-bound streams are not necessarily supporting stream operations, not to mention performance. So, if you are reading a pic from that stream or parsing a document, you may end up with some unexpected behavior.

On a side note, I have a related question re: performance of this code above, as you are taking some penalty with every file request. See here. And yes, you need 4.5 full .NET profile for this.