Virtual tables for Tasks, Meetings, Files
A new capability with this release is a set of Virtual tables. These enable developers to interact with Graph via OData APIs.
The Collaboration controls core solution includes a set of virtual tables, which can be used for programmatic access to the data created by the Collaboration controls.
Note
Currently, Collaboration controls are available only in public developer preview.
Tip
Virtual tables also known as virtual entities, enable the integration of data residing in external systems by seamlessly representing that data as tables in Microsoft Dataverse, without replication of data and often without custom coding.
The external system that is used by the Collaboration controls is Microsoft Graph. There are virtual tables for group calendar events, booking appointments, planner plans or tasks and SharePoint drives, folders, and files.
This article provides samples, which demonstrate how to access the virtual tables using the Dataverse REST API to perform CRUD (Create, Read, Update, and Delete) operations.
Tip
For more information on the Dataverse REST API, see use the Microsoft Dataverse Web API.
- Virtual tables use the standard Dataverse Web API, which makes it easy to use the virtual tables to populate data in your application.
- Virtual tables implement complex workflows required to support Collaboration controls and these execute within Microsoft data centers for optimum performance.
- Virtual tables use the standard Dataverse logging and monitoring capabilities.
After you install the Collaboration controls, the virtual tables can be treated as another service to your application that can depend on.
Pre-requisites
To follow along with this article, you need:
- A Dataverse environment where the Collaboration controls have been installed.
- A user account in the Dataverse environment, which has the Collaboration controls User role assigned to it.
- A third-party tool, for example, Post man or some custom C# code that allows you to authenticate to Microsoft Dataverse instances and to compose and send Web API requests and view responses.
Tip
Microsoft provides information on how to configure a Postman environment that connects to your Dataverse instance and use Postman to perform operations with the Web API. See Use Postman with Microsoft Dataverse Web API.
Virtual tables sample scenario
The scenario described in this guide uses the Planner Plan and Task virtual tables. The scenario described is the same one that the Tasks Collaboration control uses. From a user perspective the scenario shows how a Planner Plan, and several Tasks are created and associated with a specific business record. The scenario goes on to show how to retrieve the tasks associated with the business record and how to read, update, and delete a specific planner task.
The following sequence diagram explains the interaction between the client, which could be the Tasks collaboration control, the Collaboration API and the Planner Plan and Task virtual tables.
Virtual tables basic operations
This section describes the HTTP requests and responses for each step in the sample scenario.
Task 1: Retrieve the Group ID
Retrieve the Group ID used in settings for your Collaboration.
Note
The user you use to create the Plan in the subsequent tasks, must be a member of this group. If not you will get 403 Forbidden response.
Task 2: Begin a Collaboration session
A collaboration session is a record in the collaboration root table, which allows you to associate multiple collaborations, for example, tasks, events, appointments with a business record.
A collaboration session allows you to perform operations such as list of the calendar events associated with a business record, for example, an inspections application.
HTTP/1.1 POST https://[Organization URI]/api/data/v9.0/m365_begincollaborationsession
{
"applicationName": "{{applicationName}}",
"collaborationRootEntityId": "{{collaborationRootEntityId}}",
"collaborationRootEntityName": "{{entityName}}"
}
applicationName
: Unique name for the applicationcollaborationRootEntityName
: Name of the business record entitycollaborationRootEntityId
: Primary key (ID) of the specific business record
Keep track of the collaborationRootId
as it is needed in subsequent requests.
Task 3: Create a Planner Plan
Create a Planner Plan and associate it with the collaboration session created above with Group ID
and collaborationRootId
.
HTTP/1.1 POST https://[Organization URI]/api/data/v9.0/m365_graphplannerplans
{
"m365_collaborationrootid": "{{collaborationRootId}}",
"m365_owner": "{{groupId}}",
"m365_title": "{{planTitle}}"
}
collaborationRootId
: Identifies the collaboration session we want to associate this plan with, use the value from task 2groupId
: Identifies the group who owns this plan, use the value from step 1planTitle
: Title for the plan
Keep track of them365_id
as it is needed in subsequent requests.
Task 4: Create a Planner Task
Create a Planner Task with PlanId
and collaborationRootId
. you can create several Planner Tasks and associate them with the collaboration session created earlier.
HTTP/1.1 POST https://[Organization URI]/api/data/v9.0/m365_graphplannertasks
{
"m365_collaborationrootid": "{{collaborationRootId}}",
"m365_planid": "{{planId}}",
"m365_title": "{{taskTitle}}",
"m365_duedatetime": "2022-05-04T08:00:00Z",
"m365_assignments": "{\"me\":{\"orderHint\":\" !\",\"@odata.type\":\"#microsoft.graph.plannerAssignment\"}}"
}
collaborationRootId
: Identifies the collaboration session we want to associate this plan with, use the value from task 2planId
: Identifies the plan this task will be assigned to, use the value from the previous steptaskTitle
: Title for the task
Keep track of the m365_graphplannertaskid
as it is needed in subsequent requests.
Note
The m365_graphplannertaskid
is the primary key of the record in the Planner Task virtual table. All subsequent requests to the virtual table to interact with this record must use this primary key. This will be referred to as the plannerTaskId
in subsequent steps in this document.
You should repeat this step to create multiple tasks in the plan.
Task 5: Retrieve Associated Planner Tasks
Retrieve Associated Planner Tasks with collaborationRootId
associated with the collaboration session created previously.
HTTP/1.1 GET https://[Organization URI]/api/data/v9.0/ m365_graphplannertasks?$filter=m365_collaborationrootid eq '{{collaborationRootId}}'&$select=m365_graphplannertaskid,m365_title,m365_createddatetime
$filter
: Use the $filter system query to request records associated with the collaboration session (by specifying the ID of the collaboration root record).$select
: Use the $select system query option to request specific properties.
Keep track of the m365_id‘s
as IDs will be needed in subsequent requests.
Task 6: Retrieve a Planner Task
Retrieve a Planner Task with PlannerTaskID
to perform a Read operation on one of the planner tasks created earlier.
HTTP/1.1 GET https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
plannerTaskId
: The primary key for the planner task record is them365_graphplannertaskid
property.
Keep track of the @odata.etag
property and them365_graphplannertaskid
property as these are needed to perform update or delete operations.
Task 7: Update a Planner Task
Update a Planner Task with PlannerTask ID
to perform an Update operation on one of the planner tasks created in the previous step. To update a planner task, execute the following request:
HTTP/1.1 PATCH https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
- Header: If-Match: {{@odata.etag}}
{
"m365_title": "{{$planTitle}}"
}
@odata.etag
: Etag for the task, you must perform a read to retrieve the most up-to-date version.planTitle
: Updated title for the task
Task 8: Delete a Planner Task
Delete a Planner Task with PlannerTask ID
to perform a Delete operation on one of the planner tasks created in the previous step. To delete a planner task, execute the following request:
HTTP/1.1 DELETE https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
@odata.etag
: Etag for the task, you must perform a read to retrieve the most up-to-date version.
Task 9: Update a Planner Task details
Update a Planner Task with PlannerTask ID
to perform an update operation on one of the planner tasks created in the previous step.
HTTP/1.1 PATCH https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
Header: If-Match: {{@odata.etag}}
{
"m365_title": "{{$planTitle}}",
"m365_details": "{\"@odata.etag\":\"{{details.etag}}\",\"description\":\"Updated Task Description\"}"
}
@odata.etag
: Etag for the task, you must perform a read to retrieve the most up to date version.planTitle
: Updated title for the task.@details.etag
: Etag for the task details, you must perform a read using the query $select query parameter to include them365_details
column to retrieve the most up to date version. This value is included in them365_details
column of the response. This value isn't the same as the@odata.etag
because in the Planner backend, the Task and its details are stored separately.
Note
You can set the If-Match
header to be '*' and then you'll not need to provide any etag values, but your changes will always overwrite the task and it’s details.
Virtual tables authorization
Following are the authorization steps required to make HTTP requests using the Virtual tables in the Collaboration controls solution.
Azure app registration
To acquire the correct bearer token, an app registration in Azure is required. For more information on app registrations, see register an app.
Create an app registration in the Azure portal to authenticate.
Browse to Certificates & secrets.
Create a new client secret.
Important
Make sure to copy the secret value and store for later use. You will not be able to access it again after leaving the current page.
Browse to API Permissions.
Add the user_impersonation delegated permission from Dynamics CRM.
Grant admin consent for this permission.
Browse to Manifest.
Set the value of the following attributes to true:
- oauth2AllowIdTokenImplicitFlow
- oauth2AllowImplicitFlow
Select Save.
PowerApps environment permissions
After the app registration has been set up, you must set up an application user in PowerApps environment. This allows you to authenticate with the correct Dynamics scopes that were configured earlier.
Open the Power Platform Admin Center.
Browse to Environments > Your_Environment > Users > App Users List.
Select New App User and select your Azure app registration.
Select Edit Security Roles and assign the System Administrator role to the app user.
- The System Administrator role is applied to allow authentication for any users that have a lower security role. For example, Collaboration controls User.
- This can be restricted by applying a lower role to the application. For example, Collaboration controls Administrator.
Getting the bearer token
After completion of Azure app registration and PowerApps environment permissions, send the following HTTP request to get the Bearer token.
POST https://login.microsoftonline.com/<AZURE_APP_TENANT_ID>/oauth2/token
- Content-Type: application/x-www-form-urlencoded
- client_id: <AZURE_APP_CLIENT_ID>
- &client_secret: <AZURE_APP_CLIENT_ID>
- &resource: https://<RESOURCEURL>/
- &username: <USERNAME>
- &password: <PASSWORD>
- &grant_type: Password
Important
Make sure to include the trailing forward slash on the resource parameter. If not you will get an error related to Graph scopes when calling the virtual table.
From the response payload, copy the value of the access_token property. You can then pass this Bearer token as the part of the authorization header when making requests to the Virtual tables.
Virtual tables error handling
Virtual tables error handling describes common error scenarios and how the virtual tables respond.
Attempt to create a virtual record without a Collaboration session
A valid collaboration session is required for every request to create a virtual record. When a virtual record is created, the virtual table creates a collaboration map record, which includes the virtual record primary key, entity name and the external ID that is, Graph resource ID. This collaboration map is associated with a collaboration session, and this is how the Collaboration controls keep track of the collaborations associated with a business record.
HTTP/1.1 POST https://[Organization URI]/api/data/v9.0/m365_graphplannertasks
{
"m365_planid": "{{planId}}",
"m365_title": "{{taskTitle}}",
"m365_duedatetime": "2022-05-04T08:00:00Z",
"m365_assignments": "{\"me\":{\"orderHint\":\" !\",\"@odata.type\":\"#microsoft.graph.plannerAssignment\"}}"
}
The collaborationRootId
property is missing from the request.
To resolve this issue, you must always provide a valid collaborationRootId
property when creating a virtual record.
Attempt to read a virtual record without a Collaboration map
Virtual tables allow you to execute requests, which return collections of virtual records. We saw this earlier in this document where we requested all the planner tasks associated with a specific collaboration session. It's also possible to request all the planner tasks associated with a specific planner plan by using a $filter system query like this: $filter=m365_planid eq{{planId}}
. One issue that happens if you use such a query is that records are returned for planner tasks, which aren't associated with a collaboration session that is, planner tasks that were created by a means other than using a Collaboration control. If you attempt to read, update, or delete such a record, the request fails because the virtual table can't find the associated collaboration map.
HTTP/1.1 GET https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
The plannerTaskId
property is associated with a planner task, which was created using the Planner web interface and so doesn't have a collaboration map record.
To resolve this issue, you must check the error message in the response and if it's set to the message shown above this means the virtual record isn't associated. To create an association for this record, you must call Associate Collaboration Map - REST API.
Attempt to read a virtual record and the Graph resource has been deleted
Related to the previous error, you need to handle the case where a Graph resource has been deleted but the client still has a reference to the deleted virtual record. This can happen if another user deleted the record. If you attempt to read, update, or delete such a record, the request fails because the virtual table can't retrieve the resource from Graph.
HTTP/1.1 GET https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
The plannerTaskId
property is associated with a planner task, which was deleted.
This case must be handled by any client code, which retrieves virtual records as another user can delete the associated Graph resource at any time.
Attempt to update a virtual record with an invalid @odata.etag
The @odata.etag
property is used for data concurrency and to prevent the over writing of the same record if it has been updated by another user. When, a record is read the current etag is returned, and remains valid until the record is changed. The etag should be included in any update request and are checked before the operation completes. If the record was changed by another user since the current user read the record, then the current users update request fails.
If you perform two updates requests using the same @odata.etag, then the second request fails:
HTTP/1.1 PATCH https://[Organization URI]/api/data/v9.0/m365_graphplannertasks({{plannerTaskId}})
Header: If-Match: {{@odata.etag}}
{
"m365_title": "{{$planTitle}}"
}
Querying for Associated Virtual Records
In Task 5 of above, described how to Retrieve Associated Planner Tasks. This operation is supported for all of the virtual tables. When executing this request, you must include a $filter
query, which specifies the Collaboration Root ID as shown below:
HTTP/1.1 GET https://[Organization URI]/api/data/v9.0/ m365_graphplannertasks?$filter=m365_collaborationrootid eq '{{collaborationRootId}}'&$select=m365_graphplannertaskid,m365_title,m365_createddatetime
- Other filtering options can't be combined with this
$filter
query and if there they'll be ignored. - Other filtering must be performed directly on the response from the request.
Querying for Virtual records with required key attributes
When, Dataverse Web API is called to retrieve multiple records from the following virtual tables a mandatory key attribute is required. Graph Booking Appointments requires a valid m365_bookingbusinessid
is included in the query. If the key attribute isn't provided, then the request fails as follows:
HTTP/1.1 400 Bad Request
{
"error": {
"code": "0x80048d0b",
"message": "Key attribute is missing: 'm365_bookingbusinessid'.",
….
}
}
To fix this problem, change the request to this format:
HTTP/1.1 GET https://[Organization URI]/api/data/v9.0/ m365_graphbookingappointments?$filter=m365_bookingbusinessid eq '{{bookingBusinessId}}'
Creating virtual records and Graph access control
The virtual tables honor the access control specified for Microsoft Graph. The virtual tables won't permit operations that the user couldn't perform using the Microsoft Graph API. For example, if the user you use to create the Plan is Task 3 and isn't a member of group you use then you get 403 Forbidden responses.
See also
Feedback
Submit and view feedback for