This tip explains how Client Object Model can be utilized for copying documents with versions from SharePoint 2010 to SharePoint 2013 Online document library.
Assemblies
You need to refer following assemblies with version 15.0.0.0:
Microsoft.SharePoint.Client
Microsoft.SharePoint.Client.Runtime
Using the Code
There are few things to consider before uploading files with versions to a document library programmatically.
- Ensure that versioning is enabled in the library settings.
- Checked-out files cannot be moved using this method. So, check-in all the files before copying.
- If we update the properties of file versions (like- created and created by fields) then a new version will be created with the updated details. Same applies to the latest version. The functionality to save document metadata without creating a version is provided in SharePoint Server Object Model and not in Client Object Model. Refer https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistitem.systemupdate.aspx .
For explanation, I have divided the code in following steps:
Fetch the target folder, where you want to copy the files.
Folder targetSiteFolder = tContext.Web.GetFolderByServerRelativeUrl(targetFolderUrl);
tContext.Load(targetSiteFolder);
try
{
tContext.ExecuteQuery();
}
catch (Exception ex)
{
}
Fetch the sourceFolder from where documents need to be copied.
Folder sourceFolder = sContext.Web.GetFolderByServerRelativeUrl(sourceFolderUrl);
sContext.Load(sourceFolder.Files, files => files.Include(
file => file.ListItemAllFields
));
try
{
sContext.ExecuteQuery();
}
catch (Exception e)
{
}
If you need to fetch the folders as well, insert the below code before try..catch block.
sContext.Load(sourceFolder.Folders, folders => folders.Include(
folder => folder.Name,
folder => folder.ServerRelativeUrl,
folder => folder.Files.Include(
sFile => sFile.ListItemAllFields
)
).Where(folder => folder.Name != "Forms"));
Fetch file versions from source folder.
int fileCount = sourceFolder.Files.Count;
for (int i = 0; i < fileCount; ++i)
{
Microsoft.SharePoint.Client.File sFile = sourceFolder.Files[i];
FileVersionCollection sourceFileVersions = sFile.Versions;
sContext.Load(sourceFileVersions, fileVersions => fileVersions.Include(
version => version.Url,
version => version.VersionLabel,
version => version.CheckInComment
));
try
{
sContext.ExecuteQuery();
}
catch (Exception e)
{
}
}
Upload files to target folder.
A separate method handles the task of uploading files to the target folder. We will be uploading all the versions first and then the major version.
private static void UploadFiles(string sourceFileUrl, Folder targetFolder, string fileName)
{
FileCreationInformation targetFileVersionCreationInfo = new FileCreationInformation();
targetFileVersionCreationInfo.Overwrite = true;
try
{
WebRequest request = HttpWebRequest.Create(sourceFileUrl);
request.Credentials = sContext.Credentials;
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
byte[] verBuffer = new byte[32768];
using (MemoryStream versionMS = new MemoryStream())
{
int read;
while ((read = stream.Read(verBuffer, 0, verBuffer.Length)) > 0)
{
versionMS.Write(verBuffer, 0, read);
}
versionMS.Seek(0, SeekOrigin.Begin);
targetFileVersionCreationInfo.ContentStream = versionMS;
tContext.RequestTimeout = System.Threading.Timeout.Infinite;
targetFileVersionCreationInfo.Url = targetFolder.ServerRelativeUrl + "/" + fileName;
Microsoft.SharePoint.Client.File targetVersionFile = targetFolder.Files.Add(targetFileVersionCreationInfo);
try
{
tContext.ExecuteQuery();
}
catch (Exception ex)
{
}
}
}
}
}
catch (Exception ex)
{
}
}
When uploading versions to the target folder, we need to upload each version file in the same sequence.
if (sourceFileVersions.AreItemsAvailable)
{
foreach (FileVersion fileVer in sourceFileVersions)
UploadFiles(sContext.Url + "/" + fileVer.Url, targetFolder, sourceItem["FileLeafRef"].ToString());
}
After uploading versions, we will be uploading the main document (latest version).
UploadFiles(sourceItem["FileRef"].ToString(), targetFolder, sourceItem["FileLeafRef"].ToString());