Jordumus
Jordumus

Reputation: 2783

Sharepoint CSOM Copy file to other site collection

I want to copy a document from a document library, with all the attached metadata, from one library to another one in another site collection.

I want to do this in a Remote Event Receiver, in c#.

My problem is mostly: how to I start with this? If it's within the same site collection, I can just copy the document to the new library within the same context, but I suppose I need to work in different contexts now?

This is my code as for now:

//Get current Item
                List curList = clientContext.Web.Lists.GetById(properties.ItemEventProperties.ListId);
                ListItem curItem = curList.GetItemById(properties.ItemEventProperties.ListItemId);

                clientContext.Load(curItem);
                clientContext.ExecuteQuery();

                string sNewSite = "url.toOtherSitecollection.com";

                //Can we attempt contextception?
                using (ClientContext siteCollContext = new ClientContext(sNewSite))
                {

                    List destinationList = siteCollContext.Web.Lists.GetByTitle("DocumentLibrary_0001");
                    Folder destinationFolder = siteCollContext.Web.GetFolderByServerRelativeUrl("DocumentLibrary_0001");

                    FileCreationInformation newFileCreation = new FileCreationInformation { Content = Convert.FromBase64String(curItem.ToString()), Overwrite = true };

                    File newFile = destinationFolder.Files.Add(newFileCreation);

                    ListItem newItem = newFile.ListItemAllFields;



                    //Copy all the metadata as well.
                    try
                    {
                        newItem["..."] = curItem["..."];
                        //And all other metadata fields...

                    }
                    catch
                    {
                        //Log this.
                    }

                    newItem.Update();
                    siteCollContext.ExecuteQuery();
                }

Upvotes: 2

Views: 5308

Answers (1)

KiteCoder
KiteCoder

Reputation: 2452

Had a similar situation, here is my solution for reference:

  1. Create a ClientContext for the origin and destination site, with auth
  2. Make the call to the origin site to open the file information for the file we want to copy
  3. Read Stream from FileInformation into MemoryStream that will be used as the Content parameter of the file creation info for the new copied file
  4. Add the new FileCrationInformation to the destination file

    static private void CopyFile()
    {
    
        ClientContext contextOrigin = new ClientContext(originSiteURL);
        ClientContext contextDestination = new ClientContext(destinationSiteURL);
    
        contextOrigin.Credentials = new SharePointOnlineCredentials(originUser, originSecurePassword);
        contextDestination.Credentials = new SharePointOnlineCredentials(destinationUser, destinationSecurePassword);
    
        //Grab File
        FileInformation fileInformation = Microsoft.SharePoint.Client.File.OpenBinaryDirect(contextOrigin, "/path/to/Document.docx"); //Server relative url
        contextOrigin.ExecuteQuery();
    
        //Read Stream
        using (MemoryStream memoryStream = new MemoryStream())
        {
            CopyStream(fileInformation.Stream, memoryStream);
            memoryStream.Seek(0, SeekOrigin.Begin);
    
            //Create Copy
            var fileCreationInfo = new FileCreationInformation
            {
                ContentStream = memoryStream,
                Overwrite = true,
                Url = Path.Combine("path/to/", "CopiedDocument.docx")
            };
    
            var uploadFile = contextDestination.Web.RootFolder.Files.Add(fileCreationInfo);
            contextDestination.Load(uploadFile);
            contextDestination.ExecuteQuery();
    
        }
    }
    

Copy Stream method was found to do an in memory copy of the existing stream into the new one. It seems that the FileCreationInfo stream cannot be directly assigned from the FileInformation stream without copying it locally.

    static private void CopyStream(Stream source, Stream destination)
    {
        byte[] buffer = new byte[32768];
        int bytesRead;
        do
        {
            bytesRead = source.Read(buffer, 0, buffer.Length);
            destination.Write(buffer, 0, bytesRead);
        } while (bytesRead != 0);
    }

Using FileInformation copies metadata as well.

Upvotes: 1

Related Questions