CellStorage.svc – Intelligent Updating with Office Clients

In one of my previous posts, I came to an unlikely conclusion that Office Clients don't support delta updates as has been so widely marketed.  This was because on every single client I had tested it on, never did it make such an intelligent call.  Since I have two of four chapters done for our upcoming book, I had some time and decided to install windows 8 on a 120GB SSD drive on my laptop.  After doing so, I also decided to install Office 2013 to see what the experience would be like. Not bad, a lot of re-learning to do, but hey, I'm an MCT, we love learning new stuff.  Sooo, I thought, let's try my previous tests that have subsequently failed so many times on this freshly installed OS and Office Client. To my surprise, something different happened when saving and editing SharePoint stored Office XML documents. 

The reason the previous Office clients I was working didn't do the delta updates is because they failed to make the proper calls to cellstorage.svc.  The HTTP request headers appear to be correct, but it doesn't send a body, which is the most important part of the request.  When this happens, it falls back to "FULL" update mode and every time you make a change, the full file is sent using an HTTP PUT request (no call to cellstorage.svc is made after the first failure).  Delta updates only support Office XML documents. The reason they are only Office XML is that deep inside cellstorage it makes a call to create a pointer to an XmlReader object.  Obviously, the older files are not based on this file format and an attempt to read them is futile, therefore, you won't have any calls to cellstorage.svc, but simply the regular HTTP PUT calls.

Again, until today I was not able to get it to work. But now is a different story.  As far as what happens when it does work, this POST will help you.  I am working with several others to figure out why my other clients did not work (more to come later).

CellStorage supports various different command types (not sure the entire set, but this is a lot of them):

  • GetDocMetaInfo
  • WhoAmI
  • ServerTime
  • Cell (get and set)
  • Coauth
  • SchemaLock
  • ReleaseLock

There is a standard process to this:

  • First step is to send a request for the Document MetaInfo
  • Second step is to actually get the parts of the document that are being viewededited at that moment (cell get)
  • Third step is to request to start editing the document (requesting a schema lock)
  • Fourth step is send back any changes that a person makes (cell set)
  • Last step is to tell the server you are done (release the schema lock)

During this entire process, the client will ping the sharedaccess.asmx web service to ensure that it is the only one editing the document.  This is done about every 20 seconds.  As part of the request, it is looking for the ETag to change.  If it has changed, that means someone updated the document and the version you have is now old and you will need to refresh your copy, or overwrite what they did.  This scenario should never happen, but it looks like they attempt to check that it somehow does (it is MicrosoftSharePoint right?).

Some interesting facts:

  • When you press Ctrl-S and you haven't made any changes, it doesn't save the file, but it does do a call for GetDocMetaInfo.  So although it is not as expensive as previous versions were, there is still a cost to this (the DocProps are HUGE)
  • More to come…

The following APPENDIX is a series of CellStorage calls for each of the steps above:

APPENDIX: 

The first request (Doc MetaInfo) looks like this:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<RequestCollection CorrelationId="{5E1AF699-7B07-4FF3-ADCA-16E1E40201CC}" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Request Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="15.0.4420.1017" MetaData="1031" RequestToken="1">
<SubRequest Type="GetDocMetaInfo" SubRequestToken="1"/>
<SubRequest Type="WhoAmI" SubRequestToken="2"/>
</Request>
</RequestCollection>
</s:Body>
</s:Envelope>

The response is this:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ResponseVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<ResponseCollection WebUrl="http://www.sanspug.org" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Response Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" RequestToken="1" HealthScore="0">
<SubResponse SubRequestToken="1" ErrorCode="Success" HResult="0">
<SubResponseData>
<DocProps>
<Property Key="vti_internalversion" Value="513"/>

</DocProps>
<FolderProps>
<Property Key="vti_hassubdirs" Value="true"/>
…</FolderProps>
</SubResponseData>
</SubResponse>
<SubResponse SubRequestToken="2" ErrorCode="Success" HResult="0">
<SubResponseData UserName="Chris Givens" UserLogin="i:0#.w|chrisgivensadministrator" UserEmailAddress="givenscj@hotmail.com" UserSIPAddress=""/>
</SubResponse>
</Response>
</ResponseCollection>
</s:Body>
</s:Envelope>

The second request (get doc parts) is like this:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<RequestCollection CorrelationId="{459EA7C7-7B07-4FF3-ADCA-16E1E40201CC}" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Request Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="15.0.4420.1017" MetaData="1031" RequestToken="1">
<SubRequest Type="ServerTime" SubRequestToken="1"/>
<SubRequest Type="Cell" SubRequestToken="2">
<SubRequestData PartitionID="383adc0b-e66e-4438-95e6-e39ef9720122" BinaryDataSize="103">DQALAJzPKfM5lAabBgIAAO4CAACqAiAAjBCEGZNL606zIJGUMtblk1oEFgANbXN3b3JkB3dpbnoCCABFFOUPdwEWAgYAAwUAigICAADaAgYAAwAAygIIAAgAgAOEAEELAawCAFUDAQ==</SubRequestData>
</SubRequest>
<SubRequest Type="Cell" SubRequestToken="3">
<SubRequestData GetFileProps="true" BinaryDataSize="103">DQALAJzPKfM5lAabBgIAAO4CAACqAiAAjBCEGZNL606zIJGUMtblk1oEFgANbXN3b3JkB3dpbnoCCABFFOUPdwEWAgYAAwUAigICAADaAgYAAwAAygIIAAgAgAOEAEELAawCAFUDAQ==</SubRequestData>
</SubRequest>
<SubRequest Type="Cell&quo
t; SubRequestToken="4">
<SubRequestData PartitionID="7808f4dd-2385-49d6-b7ce-37aca5e43602" BinaryDataSize="103">DQALAJzPKfM5lAabBgIAAO4CAACqAiAAjBCEGZNL606zIJGUMtblk1oEFgANbXN3b3JkB3dpbnoCCABFFOUPdwEWAgYAAwUAigICAADaAgYAAwAAygIIAAgAgAOEAEELAawCAFUDAQ==</SubRequestData>
</SubRequest>
<SubRequest Type="Cell" SubRequestToken="5">
<SubRequestData BinaryDataSize="88">DQALAJzPKfM5lAabBgIAAO4CAACqAiAAjBCEGZNL606zIJGUMtblk1oEFgANbXN3b3JkB3dpbnoCCABFFOUPdwEWAgYAAxcAAgQIAAQ1DAALAawCAFUDAQ==</SubRequestData>
</SubRequest>
<SubRequest Type="GetVersions" SubRequestToken="6"/>
</Request>
</RequestCollection>
</s:Body>
</s:Envelope>

The response is this (but also included the binary that was requested in the request after the XML part of the response):

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ResponseVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<ResponseCollection WebUrl="http://www.sanspug.org" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Response Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" RequestToken="1" HealthScore="0">
<SubResponse SubRequestToken="1" ErrorCode="Success" HResult="0">
<SubResponseData ServerTime="634934067280000000"/>
</SubResponse>
<SubResponse SubRequestToken="2" ErrorCode="Success" HResult="0">
<SubResponseData>DAALAJ3PKfM5lAabFgMCAACsAgAMWkCfInndLk8SpahJoDsL3N5J72OAed0uTxKlqEmgOwvc3knvYz9FAAAAAAAAA4gEAAAFVQ4CBgADBQD6AigAQJ8ied0uTxKlqEmgOwvc3knvYwCEACYCIAATHwkQgsj7QJiGZTP5NMIdbAFwWQwcuPLQK0r+TVOn9MDyqn7BNTEAEFAFZRBVAGgpfUBUooP7XAJQAFAAUAAAcLkMWcPYYK6I7UOVZMRDNVJSnZUxADtQMYDEgGKDDF05g8hQM1MOXDSAwFADUwxcMHzIZDZmzFw4iMSEYoONXTF90Ggmc01bYYWEXdZSzWhico1lY1ZNaTh1wVAAALUTASYCIAAO6XY6MoAMTbnd88ZQKUM+TAEgJgwcuPLQK0r+TVOn9MDyqn7BAwClEwFBBwGLAQ==</SubResponseData></SubResponse><SubResponse SubRequestToken="3" ErrorCode="Success" HResult="0">
<SubResponseData Etag="&quot;{2EC13881-6761-4F26-A5AC-4CBBC5F4E8E0},2&quot;" CreateTime="129677043240000000" HaveOnlyDemotionChanges="False" LastModifiedTime="129677044800000000" ModifiedBy="System Account">
<xop:Include href="cid:http://tempuri.org/1/634933491321512406" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
</SubResponseData>
</SubResponse>
<SubResponse SubRequestToken="4" ErrorCode="Success" HResult="0">
<SubResponseData>DAALAJ3PKfM5lAabFgMCAACsAgAMWkCjInndLk8SpahJoDsL3N5J72OAed0uTxKlqEmgOwvc3knvY0dFAAAAAAAAA4gEAAAFVQ4CBgADBQD6AigAQKMied0uTxKlqEmgOwvc3knvYwCEACYCIAAO6XY6MoAMTbnd88ZQKUM+TAEgJgwcuPLQK0r+TVOn9MDyqn7BAwAgJgyZIgShWw0pQpGd0oV6Kr7gAAClEwEmAiAAEx8JEILI+0CYhmUz+TTCHWwBcFkMHLjy0CtK/k1Tp/TA8qp+wTUxABBQBWUQVQBoKX1AVKKD+1wCUABQAFAAAHC5DFnD2GCuiO1DlWTEQzVSUp2VMQA7UDGAxIBigwxdOYPIUDNTDlw0gMBQA1MMXDB8yGQ2ZsxcOIjEhGKDjV0xfdBoJnNNW2GFhF3WUs1oYnKNZWNWTWk4dcFQAAC1EwFBBwGLAQ==</SubResponseData></SubResponse><SubResponse SubRequestToken="5" ErrorCode="Success" HResult="0">
<SubResponseData HaveOnlyDemotionChanges="False">DAALAJ3PKfM5lAabFgMCAACsAgBVDgIGAAMXAAoEKgBUqbSHwoLARZ4MOEP3qCkZ6gQENQwHAYsB</SubResponseData></SubResponse><SubResponse SubRequestToken="6" ErrorCode="Success" HResult="0">
<GetVersionsResponse>
<GetVersionsResult>
<results>
<list id="{713BA73C-EFCD-49C9-B23D-8A2106868919}"/>
<versioning enabled="0"/>
<settings url="http://www.sanspug.org/_layouts/15/LstSetng.aspx?List={713BA73C-EFCD-49C9-B23D-8A2106868919}"/>
<result version="@1.0" url="http://www.sanspug.org/Presentations/Safety Plan Template.docx" created="12/6/2011 8:08 PM" createdRaw="2011-12-07T04:08:00Z" createdBy="SHAREPOINTsystem" createdByName="System Account" size="30106" comments=""/>
</results>
</GetVersionsResult>
</GetVersionsResponse>
</SubResponse>
</Response>
</ResponseCollection>
</s:Body>
</s:Envelope>

The request that drives the saving of a part back is (also included is a multi part binary that has the changes):

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<RequestCollection CorrelationId="{71E42242-7B07-4FF3-ADCA-16E1E40201CC}" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Request Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="15.0.4420.1017" MetaData="7" RequestToken="1">
<SubRequest Type="Coauth" SubRequestToken="1">
<SubRequestData CoauthRequestType="RefreshCoauthoring" SchemaLockID="29358EC1-E813-4793-8E70-ED0344E7B73C" ClientID="{7D99133D-52B2-44E4-BCFC-A56DBD9BE639}" Timeout="3600"/>
</SubRequest>
<SubRequest Type="SchemaLock" SubRequestToken="2" DependsOn="1" DependencyType="OnNotSupported">
<SubRequestData SchemaLockRequestType="RefreshLock" SchemaLockID="29358EC1-E813-4793-8E70-ED0344E7B73C" ClientID="{7D99133D-52B2-44E4-BCFC-A56DBD9BE639}" Timeout="3600"/>
</SubRequest>
<SubRequest Type="Cell" SubRequestToken="3" DependsOn="2" DependencyType="OnSuccessOrNotSupported">
<SubRequestData Coalesce="true" CoauthVersioning="true" GetFileProps="true" BypassLockID="29358EC1-E813-4793-8E70-ED0344E7B73C" SchemaLockID="29358EC1-E813-4793-8E70-ED0344E7B73C" BinaryDataSize="32021">
<i:Include xmlns:i="http://www.w3.org/2004/08/xop/include" href="cid:820fe252-7a34-4b40-802f-e666a88a8941-0@tempuri.org"/>
</SubRequestData>
</SubRequest>
</Request>
</RequestCollection>
</s:Body>
</s:Envelope>

The file update response is:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ResponseVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<ResponseCollection WebUrl="http://www.sanspug.org" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Response Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" RequestToken="1" HealthScore="0">
<SubResponse SubRequestToken="1" ErrorCode="Success" HResult="0">
<SubResponseData LockType="SchemaLock" CoauthStatus="Alone"/>
</SubResponse>
<SubResponse SubRequestToken="2" ErrorCode="DependentOnlyOnNotSupportedRe
questGetSupported" HResult="2147500037">
<SubResponseData/>
</SubResponse>
<SubResponse SubRequestToken="3" ErrorCode="Success" HResult="0">
<SubResponseData Etag="&quot;{2EC13881-6761-4F26-A5AC-4CBBC5F4E8E0},3&quot;" HaveOnlyDemotionChanges="False">DAALAJ3PKfM5lAabFgMCAACsAgBVDgIGAAMLADoEBAAAAIQAJgIgAPY1ejJhBxREloZR6QBmek2kAHgmYSrmvvwoD0GvMdRy1rRs+wDyCHgmntUZQQPX8L5QziuNKUuTBADyCFETASYCIAAO6XY6MoAMTbnd88ZQKUM+TAEgKAx+xz7RnpjZsFpTs0Q6CxcfpgwAICgUfsc+0Z6Y2bBaU7NEOgsXH6YMAKUTASYCIAATHwkQgsj7QJiGZTP5NMIdbAFwSQykwL9CeUV1ACf0G+m6m5XCJTEACVAFdAJw13VWUwNQAFAAALUTAUFKBAIAAAcBiwE=
</SubResponseData>
</SubResponse>
</Response>
</ResponseCollection>
</s:Body>
</s:Envelope>

 Closing the session request is:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<RequestVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<RequestCollection CorrelationId="{C2ADFD14-7B07-4FF3-ADCA-16E1E40201CC}" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Request Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" UserAgent="{1984108C-4B93-4EEB-B320-919432D6E593}" UserAgentClient="msword" UserAgentPlatform="win" Build="15.0.4420.1017" MetaData="1031" RequestToken="1">
<SubRequest Type="Coauth" SubRequestToken="1">
<SubRequestData CoauthRequestType="ExitCoauthoring" SchemaLockID="29358EC1-E813-4793-8E70-ED0344E7B73C" ClientID="{7D99133D-52B2-44E4-BCFC-A56DBD9BE639}"/>
</SubRequest>
<SubRequest Type="SchemaLock" SubRequestToken="2" DependsOn="1" DependencyType="OnNotSupported">
<SubRequestData SchemaLockRequestType="ReleaseLock" SchemaLockID="29358EC1-E813-4793-8E70-ED0344E7B73C" ClientID="{7D99133D-52B2-44E4-BCFC-A56DBD9BE639}"/>
</SubRequest>
</Request>
</RequestCollection>
</s:Body>
</s:Envelope>

 The response is:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><ResponseVersion Version="2" MinorVersion="2" xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
<ResponseCollection WebUrl="http://www.sanspug.org" xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Response Url="http://www.sanspug.org/Presentations/Safety%20Plan%20Template.docx" RequestToken="1" HealthScore="0">
<SubResponse SubRequestToken="1" ErrorCode="Success" HResult="0">
<SubResponseData/>
</SubResponse>
<SubResponse SubRequestToken="2" ErrorCode="DependentOnlyOnNotSupportedRequestGetSupported" HResult="2147500037">
<SubResponseData/>
</SubResponse>
</Response>
</ResponseCollection>
</s:Body>
</s:Envelope>