0

I wrote a program that opens and modifies documents in a library. I tried to set it up in a way where the program would skip documents that are opened, locked or checked-out by a user. But apparently I am doing something wrong, since Exceptions are still thrown when users have documents opened.

This is the way I have done it:

clientContext.Load(listItems, item => item.Include(i => i.File.CheckOutType, i => i.File.CheckedOutByUser, i => i.File.LockedByUser));
clientContext.ExecuteQuery();
Console.WriteLine("Opened Document.");

foreach (var file in listItems)
{
    // Checking if file is checked out or locked by a user
    if (file.File.CheckOutType == CheckOutType.None && file.File.LockedByUser != null)
    {
        // Every file needs to be loaded, so its properties can be used.
        clientContext.Load(file);
        clientContext.ExecuteQuery();

        filename = file["FileLeafRef"].ToString();
        Console.WriteLine("Working on " + filename + "..");
        currentID = file["ID"].ToString();
        FileInformation fileInformation = ClientOM.File.OpenBinaryDirect(clientContext, (string)file["FileRef"]);
        // Load each file into a memoryStream. Should prevent to much RAM usage
        using (MemoryStream memoryStream = new MemoryStream())
        {
            fileInformation.Stream.CopyTo(memoryStream);
            PresentationDocument ppt = PresentationDocument.Open(memoryStream, true);

            string rId = GetSlidePart(ppt, slideNumber - 1);
            PresentationPart pptPart = ppt.PresentationPart;
            SlidePart slide = (SlidePart)pptPart.GetPartById(rId);

            // Testing if a Group called "IDGroup" exists on the slide and if so getting it.
            GroupShape group = GetGroupShape(slide.Slide, "IDGroup");
            int maxID = GetMaxID(slide);

            // If group does not exist, add it to the slide.
            if (group == null)
            {
                // Checking if the Shapes exist on their own.
                Shape slideID = GetShape(slide.Slide, "SlideID");
                Shape linkID = GetShape(slide.Slide, "SlideIDLink");
                if (slideID != null)
                {
                    slideID.Remove();
                    slide.Slide.Save();
                }
                if (linkID != null)
                {
                    linkID.Remove();
                    slide.Slide.Save();
                }

                Console.WriteLine("IDGroup not found in " + filename + ", adding it..");

                // EditPresentation adds a shape and saves the presentation
                EditPresentation(memoryStream, clientContext, file, maxID);
            }
            else
            {
                // Here I am getting a bunch of properties to check them, leaving it out to keep this as short as possible

                // Checking all the properties in the IDGroup against the settings within the class.
                if (offsetx == xPos && offsety == yPos && extentsCx == width && extentsCy == heigth
                    && writtenID == tmpID && writtenFont == usedFont && writtenFontSize == usedFontSize
                    && writtenURL.Equals(usedURL, StringComparison.OrdinalIgnoreCase))
                {
                    Console.WriteLine("IDGroup already exists in " + filename + " and is configured correctly.");
                }
                else
                {
                    Console.WriteLine("IDGroup exists in " + filename + " but settings are wrong. Removing group and replacing it.");
                    group.Remove();
                    slide.Slide.Save();
                    EditPresentation(memoryStream, clientContext, file, maxID);
                }
            }
        }
    }
    else
    {
        Console.WriteLine("File is locked by user, skipping it.");
    }
}

This is the EditPresentation Method, in which the Exception occurs:

public static void EditPresentation(MemoryStream memoryStream, ClientContext clientContext, ListItem item, int ID)
{
    using (PresentationDocument ppt = PresentationDocument.Open(memoryStream, true))
    {
        string rId = GetSlidePart(ppt, slideNumber - 1);
        PresentationPart pptPart = ppt.PresentationPart;
        SlidePart slide = (SlidePart)pptPart.GetPartById(rId);
        ShapeTree tree = new ShapeTree();
        CommonSlideData commonSlideData1 = new CommonSlideData();

        // [..] Leaving out about 500 lines of OpenXML, there should be no relevant information in that

        // Save all your changes.
        slide.Slide.Save();
        pptPart.Presentation.Save();
    }
    // Seek the beginning of the memoryStream before writing, otherwise it (I think) try to write to the end of your file.
    memoryStream.Seek(0, SeekOrigin.Begin);
    ClientOM.File.SaveBinaryDirect(clientContext, (string)item["FileRef"], memoryStream, true);
}

Can somebody spot what I am doing wrong? This is the Exception message I get when a file is opened: enter image description here

<----------------------------UPDATE--------------------------->

I investigated some more. What I tried was to check for the Login Name of the user who locked the file like this:

Object.ReferenceEquals(null, file.File.LockedByUser.LoginName)

My reasoning being that if somebody had locked a file the Login Name should be null. But all I get are NullPointerExceptions. If I test file.File.LockedByUser for null it never is. I am getting confused to be honest..

  • I think that the error is thrown as soon as you try to use the file.File object. Have you tried to debug it? Or could you provide where the error is thrown? – Snickbrack Oct 5 '16 at 9:03
  • The error is thrown were I try to overwrite the active file with: ClientOM.File.SaveBinaryDirect(clientContext, (string)item["FileRef"], memoryStream, true) – UsefulUserName Oct 5 '16 at 9:29
  • 1
    why is it not in your startpost? where is this line in your code? I cannot help you without the full code which is needed here... – Snickbrack Oct 5 '16 at 9:30
  • Because I thought the problem was how I check for the locked files and to much code would just confuse. If file is locked it should just skip it completely so there would be no problem overwriting it (Since the program wouldn't try to do that). I will add the code though. – UsefulUserName Oct 5 '16 at 9:55
1

you are not correctly looking after user that are already using this file here:

if (file.File.CheckOutType == CheckOutType.None && file.File.LockedByUser != null)

file.File.LockedByUser != null tells the code "okay there is someone using this file" and then you call FileInformation fileInformation = ClientOM.File.OpenBinaryDirect(clientContext, (string)file["FileRef"]); which is perfectly okay cause the file will just be opened and is like a file opening on Windows which is also no issue to open a file by two person simultaniously.

But as soon as you call ClientOM.File.SaveBinaryDirect(clientContext, (string)item["FileRef"], memoryStream, true); SharePoint tries to actively using this file which is not possible because the file is already in use.

So you should check for:

if (file.File.CheckOutType == CheckOutType.None && file.File.LockedByUser != false)

maybe this will to the trick for you. And you should also wrap this if around the whole code which uses the file. Anyways you will get the same error on another line.

  • Thanks for your reply! Your explanation seems correct, I will try it out and report back. The If-Clause wraps around all the code in which the file is being modified and overwritten. – UsefulUserName Oct 5 '16 at 12:32
  • Sadly, this does not work, since file.lockedByUser expects an object user and cannot be compared to a boolean. Or am I doing something wrong? – UsefulUserName Oct 5 '16 at 16:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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