3

I have created an Office Add In that is used to upload a Word document to SharePoint, showing a list of sites/subsites and Document Libraries. After the file is uploaded I set the content type based on what is selected in the UI. The code is as follows:

using(var vs = new FileStream(documentLocation, FileMode.Open, FileAccess.Read))
{
    var fileInfo = new FileCreationInformation
    {
        ContentStream = fs,
        Url = serverRelativeFileUrl,
        Overwrite = false
    };

    uploadFile = documentLibrary.RootFolder.Files.Add(fileInfo);
    context.ExecuteQuery();

    ListItem listItem = file.ListItemAllFields;
    context.Load(listItem);
    context.ExecuteQuery();

    listItem["ContentTypeId"] = contentTypeId;
    listItem.Update();

    context.ExecuteQuery();
}

Occasionally this code fails saying that the file is locked for shared use has been modified by my user account. It seems to fail on the last ExecuteQuery() call. It is not consistent and works most of the time. Is there something wrong with the code I have, or how can I prevent this error from occurring?

Edit The error message actually says: The file has been modified by my account name...not that it is locked for shared use.

3
  • Try removing context.Load(listItem);context.ExecuteQuery(); Apr 16, 2015 at 12:58
  • @AmalHashim that doesn't solve the issue unfortunately
    – Dismissile
    Apr 16, 2015 at 14:24
  • i am not developer but i know long time ago we had issue and one of developer said, You have to wait after uploading the item then made further changes. So i dont know if their is any sleep method which you can user right after uploading the item and then apply the content type.
    – Waqas Sarwar MVP
    Apr 16, 2015 at 16:37

2 Answers 2

3
+100

Evidently this error occurs in case if file has been modified while updating the file:

listItem.Update();
ctx.ExecuteQuery();

How about this approach?

public static File UploadFile(ClientContext ctx, string sourceFilePath, string targetUrl,IDictionary<string,string> fileProperties)
{
        var targetFileUrl = String.Format("{0}/{1}", targetUrl, Path.GetFileName(sourceFilePath));
        using (var fs = new FileStream(sourceFilePath, FileMode.Open))
        {
            Microsoft.SharePoint.Client.File.SaveBinaryDirect(ctx, targetFileUrl, fs, true);
        }

        //Set properties
        var uploadedFile = ctx.Web.GetFileByServerRelativeUrl(targetFileUrl);
        var listItem = uploadedFile.ListItemAllFields;
        foreach (var p in fileProperties)
        {
            listItem[p.Key] = p.Value;   
        }
        listItem.Update();
        ctx.ExecuteQuery();
        return uploadedFile;
}

Usage

var fileProperties = new Dictionary<string, string>();
fileProperties["ContentTypeId"] = "--guid--";              
UploadFile(ctx, @"C:\Documents\SharePoint User Guide.docx", "/sites/news/Documents", fileProperties);         

It uses Microsoft.SharePoint.Client.File.SaveBinaryDirect method that does not require an ExecuteQuery method call.


Or you could apply some type of retry strategy, for example:

public static bool TryUploadFile(ClientContext ctx, string sourceFilePath, string targetUrl, IDictionary<string, string> fileProperties)
{
        using (var fileStream = new FileStream(sourceFilePath, FileMode.Open))
        {
            var fileInfo = new FileCreationInformation()
            {
                ContentStream = fileStream,
                Overwrite = true,
                Url = Path.GetFileName(sourceFilePath)
            };

            var targetFolder = ctx.Web.GetFolderByServerRelativeUrl(targetUrl);
            var uploadFile = targetFolder.Files.Add(fileInfo);
            var listItem = uploadFile.ListItemAllFields;
            foreach (var p in fileProperties)
            {
                listItem[p.Key] = p.Value;
            }

            return TrySaveListItem(listItem, TimeSpan.FromSeconds(2));
        }
}


private static bool TrySaveListItem(ListItem listItem, TimeSpan retryInterval, int retryCount = 3)
{
        while (true)
        {
            try
            {
                listItem.Update();
                listItem.Context.ExecuteQuery();
                return true; 
            }
            catch
            {
                if (--retryCount == 0) return false;
                Thread.Sleep(retryInterval);
            }
        }
}

Usage

var fileProperties = new Dictionary<string, string>();
fileProperties["ContentTypeId"] = "--guid--";              
if(TryUploadFile(ctx, @"C:\Documents\SharePoint User Guide.docx", "/sites/news/Documents", fileProperties){
   //...
}
1
  • 1
    Ended up putting retry logic in there and it eventually works.
    – Dismissile
    Apr 23, 2015 at 15:14
-1

This should work:

// the rest of your code omitted for brevity...

uploadFile = documentLibrary.RootFolder.Files.Add(fileInfo);

// Update the file metadata
uploadFile.ListItemAllFields["ContentTypeId"] = contentTypeId;
uploadFile.ListItemAllFields.Update();
clientContext.ExecuteQuery();
1
  • Nope this doesn't get rid of the issue.
    – Dismissile
    Apr 16, 2015 at 14:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.