Reputation: 2783
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
Reputation: 2452
Had a similar situation, here is my solution for reference:
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