Part 1 of in this series described how SharePoint Server to Server SharePoint integration (new to CRM2013 SP1) works from the client interface perspective. In this post I'd like to share a bit more how this all works from the server side.
Authentication
When this feature was introduced my first question was about authentication. Having created a fair number of solutions that integrated SharePoint with Dynamics CRM on the server side I knew that this is a tricky area. Since this feature is only available for CRM Online to SharePoint Online where they are in the same tenant it makes authentication slightly simpler because there is already an existing trust in place between the two servers which allows Dynamics CRM to authenticate with SharePoint and act as the calling user. The HTTP request that comes from the client is inspected by the integration component and the UPN is used to authenticate with SharePoint as the same user rather than the service account. This is acting on behalf of the user is critical because when documents are created, checked in/out or queried, it must be performed under the account of the user and not the system account. Perhaps even more important, when CRM queries for documents it will only return those that the user has access to as configured in SharePoint.
If this feature is made available for On Prem customers I would expect that a configuration would have to be made available to provide the user's SharePoint username and password to use when performing server side operations.
Query SharePoint Documents
The new SharePoint sub grid that is rendered by CRM actually uses exactly the same query mechanism as any other entity – but rather than the query being sent to the CRM Database, it is handled by the SharePoint query handler. If you fire up Advanced Find, you'll see a new Entity named 'Documents' but if you query against this entity you will get the error:

The error is given by the SharePoint FetchXml conversion to CAML only works if a specific regarding object is provided – this means that you can only return records for a specific folder, rather than all documents in all document locations. When the refresh button is clicked on the client sub-grid there is FetchXml similar to the following executed:
<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="50" returntotalrecordcount="true" >
<entity name="sharepointdocument" >
<attribute name="documentid" />
<attribute name="fullname" />
<attribute name="relativelocation" />
<attribute name="sharepointcreatedon" />
<attribute name="ischeckedout" />
<attribute name="filetype" />
<attribute name="fullname" />
<attribute name="modified" />
<attribute name="sharepointmodifiedby" />
<attribute name="relativelocation" />
<attribute name="documentid" />
<attribute name="modified" />
<attribute name="fullname" />
<attribute name="title" />
<attribute name="author" />
<attribute name="sharepointcreatedon" />
<attribute name="sharepointmodifiedby" />
<attribute name="sharepointdocumentid" />
<attribute name="filetype" />
<attribute name="readurl" />
<attribute name="editurl" />
<attribute name="ischeckedout" />
<attribute name="absoluteurl" />
<filter type="and" >
<condition attribute="regardingobjecttypecode" operator="eq" value="1" />
<condition attribute="regardingobjectid" operator="eq" value="{1EF22CCD-9F19-E411-811D-6C3BE5A87DF0}" />
</filter>
<order attribute="relativelocation" descending="false" />
</entity>
</fetch>
The interesting part here is that we can add filters not only by regarding object but we could also add our own filters for name or document type. Initially I was confused because running this Fetch query in the Xrm Toolbox FetchXml tester gave no results but as it turns out this uses the ExecuteFetchRequest rather than RetrieveMultiple and this new SharePoint integration is only implemented on the latter.
Internal Execute Messages
This new server to server functionality is exposed by a set of internal messages that are not documented in the SDK but by using Fiddler (the tool that give you super powers!), you can see these messages being called from the client when operation such as Check In/Check Out are called. Here is a list of these internal messages:
Message Name
|
Description
|
RetrieveMultipleRequest (sharepointdocument)
|
Returns a list of document names from SharePoint for a specific document location. This query is converted into SharePoint CAML on the server and supports basic filter criteria and sorting.
|
NewDocumentRequest
|
Creates a new document location and matching SharePoint folder and is called when the documents sub grid is first shown with no document locations configured.
FileName – Name of the file to create including extension (e.g. NewDocument.docx)
RegardingObjectId – Guid of the record that the document location belongs to
RegardingObjectTypeCode – Object type code of the record the document location belongs to
LocationId – The ID of the document location to add the new document to (in case there are multiple)
|
CheckInDocumentRequest
CheckOutDocumentRequest
DisregardDocumentCheckoutRequest
|
This performs the check in/out operation on a specific document in SharePoint.
Entity – The document to check in/out with the 'documentid' property populated with the List Id in SharePoint.
CheckInComments
RetainCheckOut
|
CreateFolderRequest
|
Creates a new documents location in CRM and the corresponding SharePoint folder.
FolderName – the name to give to the SharePoint folder
RegardingObjectId – Guid of the record that the document location belongs to
RegardingObjectTypeCode – Object type code of the record the document location belongs to
|
Now before you get excited you can't use these requests on the server because you will get a 'The request <Request Name> cannot be invoked from the Sandbox.' (Yes, I did try!) This is expected since the sandbox does not have access to the HTTP context that contains the information about the calling user and so the authentication with SharePoint cannot take place.
I proved this using a Custom Workflow Activity that tried to call 'CreateFolder' and you see the following error.

These requests can however be called easily from JavaScript which opens up some interesting possibilities (if a little unsupported because these messages are not actually documented the SDK at the moment):
- Automatically create a document location using a different naming convention to the standard one via JavaScript onload of a record if there isn't one already.
- Provide a custom view of SharePoint documents using fetchxml – this could even be filtered to just show a particular file type by adding a condition similar to <condition attribute="filetype" operator="eq" value="jpeg"/>
- Provide custom buttons to create documents in SharePoint.
I hope you've found this interesting - Next time I'll show you how to get around the sandbox limitation to perform server side operation on SharePoint from a CRM Plugin or Workflow Activity.
@ScottDurow