0

I'm trying to get the OneNote notebook information that is linked to my organization's CRM accounts. Each account has a OneNote book created for it that can be accessed inside of CRM.

From what I understand, I can use the SharePointDocumentLocation endpoint (found here: https://learn.microsoft.com/en-us/dynamics365/customer-engagement/web-api/sharepointdocumentlocation?view=dynamics-ce-odata-9) to get the location of the specific file if I ask for location type to be 1.

However, SharePointDocumentLocationId and SiteCollectionId don't seem to be pointing to anything on my company's sites. Should I be getting my data somewhere else?

I started searching through my company's SharePoint structure to see if I can get any hints as to where these documents may be located. My initial Postman request (getting the sites off of the root site) don't show the site that hosts our CRM documents (sites/crmdocs). I was able to find where this was stored eventually, but trying to get the OneNote notebooks stored there returns an error since we have more than 20,000 notebooks there, so I can't fetch them all. As far as I know, I'm able to get notebooks if I have the specific ID I want.

Once I fetch the CRM information, I try to send a request like this:

https://graph.microsoft.com/v1.0/sites/{myCompanyUrl},{siteCollectionId},{sharepointDocumentLocationId}/onenote/notebooks/

SiteCollectionId and SharePointDocumentLocationId are from my CRM SharePointDocumentLocation request

The error I receive is:

The requested site was not found. Please check that the site is still accessible.
Thomas
  • 35
  • 2
  • 8

1 Answers1

0

Assuming your environment is using the out of the box sharepoint site and sharepoint document location hierarchy, you can access One Note files using the following link structure:

[SharePointAbsoluteUrl]/[EntityLogicalName]/[RelativeUrl]_[RegardingObjectId]/[RelativeUrl]
  1. How to get [SharePointAbsoluteUrl] :

Querying for sharepointdocumentlocations is actually not enough because Dynamics 365 stores this information in another entity called sharepointsite. This is how you can obtain it:

        var query = new QueryExpression("sharepointsite")
        {
            ColumnSet = new ColumnSet("absoluteurl")
        };
        query.Criteria.AddCondition("IsDefault", ConditionOperator.Equal, true);
        var entityCollection = _service.RetrieveMultiple(query);

        var absoluteUrl = entityCollection[0].Attributes["absoluteurl"];

In Web API it is equivalent to:

GET https://[Your Org]/api/data/v9.0/sharepointsites?$select=absoluteurl&$filter=isdefault%20eq%20true

There can only be a default sharepoint site so this query will return a single record.

  1. How to get the remaining parts:

Fetch for sharepointdocumentlocations that have Location Type dedicated to One Note Integration:

        var query = new QueryExpression("sharepointdocumentlocation")
        {
            ColumnSet = new ColumnSet("regardingobjectid", "relativeurl")
        };
        query.Criteria.AddCondition("locationtype", ConditionOperator.Equal, 1);

        var entityCollection = _service.RetrieveMultiple(query);

In Web API it is equivalent to the following get request, don't forget to add add Prefer: odata.include-annotations="*" to your HTTP Request Headers so that it gets the lookup lookuplogicalname field:

GET https://[Your Org]/api/data/v9.0/sharepointdocumentlocations?$select=relativeurl,_regardingobjectid_value&$filter=locationtype%20eq%201

This query can return many records, I've only used the first one in the examples below for explanation purposes.

[EntityLogicalName] will be your ((EntityReference)entityCollection[0].Attributes["regardingobjectid"]).LogicalName; In Web Api will be your value._regardingobjectid_value@Microsoft.Dynamics.CRM.lookuplogicalname value.

[RelativeUrl] will be your entityCollection[0].Attributes["relativeurl"]; In Web Api will be your value.relativeurl value.

[RegardingObjectId] can be obtained with this expression ((EntityReference)entityCollection[0].Attributes["regardingobjectid"]).Id.ToString().Replace("-", "").ToUpper(); In Web Api id will be your _regardingobjectid_value value and you have to remove dashes and convert it to upper case in whatever language you are doing the request.

You should end up with an URL like this https://mycompany.sharepoint.com/account/A Datum Fabrication_A56B3F4B1BE7E6118101E0071B6AF231/A Datum Fabrication

André Cavaca
  • 510
  • 1
  • 5
  • 18
  • Thanks for your response! Are you using C# to make this request, and if so what library are you using? I was originally using NodeJS for making this request, and I do get back the "regardingObjectId", but I can't extract the LogicalName from it. – Thomas Apr 12 '19 at 04:25
  • Also, from what I understand this will get me the URL of the OneNote notebook, but in order to get its data I believe I would need to use the Microsoft Graph API, which has its certain format on how to get OneNote data. Is there a way to extract the OneNote data once I get that URL? – Thomas Apr 12 '19 at 04:27
  • I solved the first comment at least, I needed to include Prefer: odata.include-annotations="*" in the header of my request. However, I'm still uncertain on how I can use this information to retrieve the OneNote notebook by the graph api. – Thomas Apr 12 '19 at 12:54
  • @Thomas C# code uses Microsoft.Xrm.Sdk library. I've updated my answer with Web API calls so that anyone outside .NET world can use it as well. Is Graph API mandatory? Can't you just do a REST request to Sharepoint directly in node JS? – André Cavaca Apr 12 '19 at 14:09
  • I would love if it was unnecssary, but I'm not sure if I can outside of it. If I send a request to the link after I've constructed it, I receive a 403 forbidden error, likely because I'm not signed in to my organization from my code. However, I don't know how I can "sign in" to my Microsoft account via my code. I imagine I need a Bearer token, but don't know how I should get it. – Thomas Apr 12 '19 at 14:28