I had been asked to look at a SharePoint event receiver that wasn’t behaving as it should. After a document had been checked in, it would set a property and update the item. However, we were getting an error:
SPException: The file “[File Name]” is locked for exclusive use by [User]
This was unfortunate – the user was the user who’d just been making changes, and the code was running after the document had been checked in – so what gives? Well, it turns out that the message is right – the file is locked, not checked out, and a lock is not the same as a check-out.
If you look at the SharePoint object model for an SPFile you’ll notice that there are properties relating to both Check-outs and Locks (more on this later). However, they are different. It appears that:
- Check-outs are manually initiated through a user interface – either SharePoint itself, or an application like MS Word.
- Locks are automatically initiated from a client application – like Excel or Word.
Let’s look a bit at these mechanisms…
Check out is pretty simple – the user can check out a document, and while it’s checked out, only they can update it. Files remain checked out indefinitely until the user checks them in, or until an administrator removes their check-out. Checked out files are visible due to the green icon that appears on them, and there is a column on the library that shows you who the document is checked out to. So far, so normal.
Locks are performed by the Office clients. When you open a document you can open it in ‘Read-only’ or ‘Edit’ modes.
If you select Edit, the office client locks the file. There is no visual marking of this. Locks can be released, or they can expire after a time span. The office clients periodically send a heartbeat request to the server that extends their lock. You can see this in Fiddler:
The top highlighted row is the lock being applied. The second highlighted row is a heartbeat to extend the lock, which was sent about 40 minutes later.
Applying the lock sends some XML to the CellStorage.svc WCF service. Below is an example:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <RequestVersion Version="2" MinorVersion="0" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/> <RequestCollection CorrelationId="{006394CC-2EFC-41AF-8802-B846DB1522D8}" xmlns="http://schemas.microsoft.com/sharepoint/soap/"> <Request Url="http://sp/sites/Docs/Documents/Dolor%20Sit%20Amet.xlsx" RequestToken="1"> <SubRequest Type="ExclusiveLock" SubRequestToken="1"> <SubRequestData ExclusiveLockRequestType="GetLock" ExclusiveLockID="{D09051E3-8A4C-4559-82FD-DA08801E3458}" Timeout="3600"/> </SubRequest> <SubRequest Type="Cell" SubRequestToken="2" DependsOn="1" DependencyType="OnExecute"> <SubRequestData GetFileProps="true" BinaryDataSize="513">[Content 64 encoded, removed for brevity] </SubRequestData> </SubRequest> </Request> </RequestCollection> </s:Body> </s:Envelope>
Extending the lock sends:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body> <RequestVersion Version="2" MinorVersion="0" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/> <RequestCollection CorrelationId="{00891F74-2EFC-41AF-8802-B846DB1522D8}" xmlns="http://schemas.microsoft.com/sharepoint/soap/"> <Request Url="http://sp/sites/Docs/Documents/Dolor%20Sit%20Amet.xlsx" RequestToken="1"> <SubRequest Type="ExclusiveLock" SubRequestToken="1"> <SubRequestData ExclusiveLockRequestType="RefreshLock" ExclusiveLockID="{D09051E3-8A4C-4559-82FD-DA08801E3458}" Timeout="3600"/> </SubRequest> </Request> </RequestCollection> </s:Body> </s:Envelope>
You’ll notice that part of that is getting a lock – an exclusive lock, with a timeout of 1 hour. So what is with different types of lock? Well, this leads us nicely around to the object model:
An SPFile has Check-Out types of:
- Online – The file is checked out for editing on the server.
- Offline – The file is checked out for editing on the local computer.
- None – The file is not checked out.
And Lock Types of:
- Exclusive – The file is locked for editing by a single user. No other user can modify the file until the lock is released.
- Shared – The file is locked for editing by a group who are using a collaborative application. Other users are prevented from modifying the file until the lock is released.
- None – The file is not locked.
An SPFile also has a whole bunch of properties and methods related to controlling concurrent editing, several of which are now obsolete. There’s too many to list here – check the MSDN documentation.
What is that showing? Well, it shows that the different users for ‘lock’ and ‘check-out’ have been in SharePoint for a while, but that they were tied up in the checkout functionality. They’re now being separated – hence the obsolete methods.
Looking at the types of lock, it’s pretty clear that this is to support exclusive locks and shared locks, which is when you might have things like the concurrent editing of a document in Word.
These two systems are apparently now fairly independent, although they offer similar functionality.
So, to return to my problem – we’ve got a document that has been locked, but not checked out, and we’re trying to update it. The event receiver itself looked like:
class MyEventHandler : SPItemEventReceiver { public override void ItemCheckedIn(SPItemEventProperties properties) { EventFiringEnabled = false; base.ItemCheckedIn(properties); SPListItem item = properties.ListItem; item.File.CheckOut(); item["myProp"] = "Some Value"; item.Update(); item.File.CheckIn("Set myProp"); EventFiringEnabled = true; } }
The exception was being thrown on the call to item.Update(). Debugging showed that the item was locked to our user, but not checked out to them. Given that we’re only trying to update some of the properties, and after check-in at that, it seems a bit same that the Update() call fails due to the lock. However, when I then thought about it I realised that a call to .SystemUpdate() felt more appropriate. When I tried that, it worked.
Conclusions
Firstly, given that you’ve got the automatic ‘locking’ mechanism of Word, Excel, etc., I question the need to ‘force checkout’ on document libraries. It isn’t hard using those applications – if you force check-out then it simply locks and checks out the documents at the same time – but it does appear to be unnecessary.
Secondly, if you’re updating document properties using event handlers or similar, you should be aware that the Update() function obeys locks, while the SystemUpdate() function will update the item, even if it is locked.
And finally, from a developer’s standpoint, the locking functionality on an SPFile could be a useful way of ‘checking out’ a document without actually checking it out. It could actually be quite useful.
Thank you for explaining this so clearly. The locking behaviour of SharePoint has been infuriatingly obtuse, until now.
You are right that enforcing a checkout to update properties is not necessary, more so that SP does not check in the document after the edits are made.
Peter
Andrew, your blog has been so helpful. THANK YOU!!!