CSOM: How to copy a document from one document library to another documents library?

sravya shivapuram 211 Reputation points
2021-11-22T16:53:06.393+00:00

Hi,

I have a requirement to copy documents that meets a certain criteria ( i.e once a document's approval status = approved) to an Archived documents library. I am looping through all the sites and using CAML query to filter out the documents with approved status but I have no idea how to copy the document to a different library location using CSOM C# after checking this condition. Also, I need the document to be replaced in case it is already present in the archived library.

Note: The archived library is in a different site collection.

Any help is greatly appreciated. Thank you in advance.

SharePoint
SharePoint
A group of Microsoft Products and technologies used for sharing and managing content, knowledge, and applications.
9,679 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,274 questions
SharePoint Development
SharePoint Development
SharePoint: A group of Microsoft Products and technologies used for sharing and managing content, knowledge, and applications.Development: The process of researching, productizing, and refining new or existing technologies.
2,674 questions
0 comments No comments
{count} votes

Accepted answer
  1. Hendrik 91 Reputation points
    2021-11-30T22:23:22.877+00:00

    To fix the problem that the file exists you can change the code like this

    File newFile = targetFolder.Files.Add(new FileCreationInformation() {
                ContentStream = stream.Value,
                Url = targetName,
                Overwrite = true
            });
    

    For the "not visible" part. Your Reports library uses major and minor versions? So maybe your file is there but not published yet and your the user you are using is different from the user you are using for the console application? Then you are not able to see the file in the SharePoint UI.

    If thats the case you can try to add the following code, after the "Files.Add" part:

    _targetContext.Load(newFile, n => n.CheckOutType);
    _targetContext.ExecuteQuery();
    
    if(newFile.CheckOutType == CheckOutType.None){
         newFile.Publish("first version");
    } 
    else {
         newFile.CheckIn("first version", CheckinType.MajorCheckIn);
    }
     _targetContext.ExecuteQuery();
    

    This will publish the file if it is not published yet. But be careful. This code will only work in a library where versioning is activated.

    Is there anything else I can do to manually refresh the search results in SP Online?

    No in SPO you are not able to manage the search crawler like in OnPrem SharePoint.

    1 person found this answer helpful.

3 additional answers

Sort by: Most helpful
  1. Echo Du_MSFT 17,116 Reputation points
    2021-11-23T02:28:08.11+00:00

    Hello @sravya shivapuram ,

    Welcome to Q&A Forum!

    To dynamically copy the files and folders using CSOM, follow below code.

    public void CloneLibraryItems(string srcLibrary, string srcUrl, string destUrl, string userName, SecureString pwd)  
    {  
    string srclibraryname = string.Empty;  
    string fileName = string.Empty;  
    string folderPath = string.Empty;  
    try  
    {  
      
    ClientContext srcContext = new ClientContext(srcUrl);  
    ClientContext destContext = new ClientContext(destUrl);  
      
    srcContext.Credentials = new SharePointOnlineCredentials(userName, pwd);  
    srcContext.RequestTimeout = Timeout.Infinite;  
    Web srcWeb = srcContext.Web;  
    List srcList = srcWeb.Lists.GetByTitle(srcLibrary);  
    CamlQuery camlQuery = new CamlQuery();  
    camlQuery.ViewXml = “<View Scope=’RecursiveAll’><Where><Eq><FieldRef Name='_ModerationStatus' /><Value Type='ModStat'>Approved</Value></Eq></Where></View>”;  
    ListItemCollection itemColl = srcList.GetItems(camlQuery);  
    srcContext.Load(itemColl);  
    srcContext.ExecuteQuery();  
      
    destContext.Credentials = new SharePointOnlineCredentials(userName, pwd);  
    destContext.RequestTimeout = Timeout.Infinite;  
    Web destWeb = destContext.Web;  
    destContext.Load(destWeb);  
    destContext.ExecuteQuery();  
      
    string _path = destWeb.ServerRelativeUrl;  
    if (itemColl.Count > 0)  
    {  
      
    srclibraryname = itemColl[0].FieldValues[“FileDirRef”].ToString();  
    string[] srcurlSplit = srclibraryname.Split(‘/’);  
    srclibraryname = srcurlSplit[srcurlSplit.Count() – 1];  
      
    foreach (ListItem doc in itemColl)  
    {  
      
    if (doc.FileSystemObjectType == FileSystemObjectType.File)  
    {  
      
    fileName = doc[“FileRef”].ToString();  
    string[] fileNames = fileName.Split(new string[] { srclibraryname }, StringSplitOptions.None);  
    fileName = fileNames[fileNames.Count() – 1];  
      
    OSP.File file = doc.File;  
    srcContext.Load(file);  
    srcContext.ExecuteQuery();  
      
    FileInformation fileInfo = OSP.File.OpenBinaryDirect(srcContext, file.ServerRelativeUrl);  
    OSP.File.SaveBinaryDirect(destContext, _path + “/” + srclibraryname + fileName, fileInfo.Stream, true);  
      
    }  
    else if (doc.FileSystemObjectType == FileSystemObjectType.Folder)  
    {  
      
    folderPath = doc[“FileRef”].ToString();  
    string[] fileNames = folderPath.Split(new string[] { srclibraryname }, StringSplitOptions.None);  
    folderPath = fileNames[fileNames.Count() – 1];  
    folderPath = folderPath.TrimStart(new Char[] { ‘/’ });  
    //Console.WriteLine(“Folder Path :” + folderPath);  
    OSP.Folder folder = CreateFolder(destContext.Web, srcLibrary, folderPath);  
      
    }  
      
    }  
      
    }  
      
    }  
    catch (Exception ex)  
    {  
    Console.WriteLine(ex.Message);  
    }  
      
    }  
    

    Reference:

    Thanks,
    Echo Du

    =================================
    Updated Answer =============================

    Hi @sravya shivapuram ,

    private static CopyFiles()  
     {  
    	string source = "https://abc.sharepoint.com/sites/applications/appname/123456/";  
    	OfficeDevPnP.Core.AuthenticationManager authMgr = new OfficeDevPnP.Core.AuthenticationManager();  
    	string userName = "";  
    	string password = "";  
    	var secure = new SecureString();  
    	foreach (var c in password.ToCharArray()) secure.AppendChar(c);  
    	var context = authMgr.GetSharePointOnnlineAuthenticatedContextTenant(sourceUrl,userName,password);  
    	try  
    	{  
    		List targetList = context.Web.Lists.GetByTitle("");  
    		camlQuery oQuery = CamlQuery.CreateAllItemsQuery();  
    		  
    		ListItemCollection oCollection = targetList.GetItems(oQuery);  
    		context.Load(oCollection);  
    		context.ExecuteQuery();  
    		string srcUrl = "https://abc.sharepoint.com/sites/applications/appname/123456/Shared%20Documents/"  
    		string desUrl = "https://abc.sharepoint.com/sites/Archive/Records/"  
    		  
    		MoveCopyOptions mco = new MoveCopyOptions  
    		{  
    			KeepBoth = false  
    		};  
    		foreach(ListItem oItem in oCollection)  
    		{  
    			string a = oItem["FileRef"].ToString();  
    			int startInd = a.LastIndexOf("/")+1;  
    			int lastInd = (a.Length - a.LastIndexOf("/"))-1;  
    			string docTit = a.Substring(startInd,lastInd);  
    			Console.WriteLine(a.Substring(startInd,lastInd));  
    			MoveCopyUtil.CopyFile(context, srcUrl+docTit, desUrl+docTit, true, mco);  
    		}  
    		context.ExecuteQuery();  
    	}  
    }  
    

    Thanks,
    Echo Du

    ===========================================

    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. sravya shivapuram 211 Reputation points
    2021-11-29T21:50:34.45+00:00

    Thank you @Echo Du_MSFT for following up. I am now running into - ' Cannot contact site at the specified URL https://abc.sharepoint.com/sites/applications/appname/123456/Shared Documents/Book1 . There is no Web named "/sites/applications/appname/123456/Shared Documents/Book1/_vti_bin/sites.asmx" error. Here is the code that I am using to copy the document from one library to another -

                                    var bookname = item.DisplayName;  
                                    string bookLocation = $"{rootFolder.ServerRelativeUrl}/{bookname}";                                  
                                    var absoluteUrl = new Uri(ctx.Url).GetLeftPart(UriPartial.Authority) + bookLocation;  
                                    var srcUrl = absoluteUrl;  
                                    var destUrl = "https://abc.sharepoint.com/sites/Archive";  
                                    var srcLibrary = "Documents";  
                                    var destLibrary = "Records";  
      
                                    ClientContext destContext = new ClientContext(destUrl);  
                                    ClientContext srcContext = new ClientContext(srcUrl);  
                                    destContext.Credentials = SPAuth.GetSPOnlineCredentials();  
                                    srcContext.Credentials = SPAuth.GetSPOnlineCredentials();                                 
                                    Web srcWeb = srcContext.Web;  
                                    List srcList = srcWeb.Lists.GetByTitle(srcLibrary);                                 
                                    Web destWeb = destContext.Web;  
                                    destContext.Load(destWeb);  
      
                                    destContext.ExecuteQuery();  
                                    try  
                                    {  
                                        Microsoft.SharePoint.Client.File file1 = srcContext.Web.GetFileByServerRelativeUrl(bookLocation);  
                                        srcContext.Load(file1);  
                                        srcContext.ExecuteQuery();  
                                        string location = destWeb.ServerRelativeUrl.TrimEnd('/') + "/" + destLibrary.Replace(" ", "") + "/" + file1.Name;  
                                        FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(srcContext, file1.ServerRelativeUrl);  
                                        Microsoft.SharePoint.Client.File.SaveBinaryDirect(destContext, location, fileInfo.Stream, true);  
                                    }  
      
                                    catch (Exception ex)  
                                    {  
                                        telemetry.TrackException(new Exception("Failed to copy the book to archive library", ex));  
                                    }                                
                                    return true;  
                                }  
    

    The bookLocation that I am passing in as 'filepath' looks like below -
    /sites/applications/appname/123456/Shared Documents/Book1

    Please let me know if I am specifying anything incorrectly. Any help is greatly appreciated. Thank you for all your time.