Example #1
0
        private async Task HandleNotificationsAsync(NotificationPayload notifications, CancellationToken cancellationToken)
        {
            // A single webhook might get notifications from different users.
            List <WebhookTriggerData> resources = new List <WebhookTriggerData>();

            foreach (Notification notification in notifications.Value)
            {
                var subId = notification.SubscriptionId;
                var entry = await _subscriptionStore.GetSubscriptionEntryAsync(subId);

                if (entry == null)
                {
                    _log.LogError($"No subscription exists in our store for subscription id: {subId}");
                    // mapping of subscription ID to principal ID does not exist in file system
                    continue;
                }

                if (entry.Subscription.ClientState != notification.ClientState)
                {
                    _log.LogTrace($"The subscription store's client state: {entry.Subscription.ClientState} did not match the notifications's client state: {notification.ClientState}");
                    // Stored client state does not match client state we just received
                    continue;
                }

                // call onto Graph to fetch the resource
                var userId      = entry.UserId;
                var graphClient = await _clientManager.GetMSGraphClientFromUserIdAsync(userId, cancellationToken);

                _log.LogTrace($"A graph client was obtained for subscription id: {subId}");

                // Prepend with / if necessary
                if (notification.Resource[0] != '/')
                {
                    notification.Resource = '/' + notification.Resource;
                }

                var url = graphClient.BaseUrl + notification.Resource;

                HttpRequestMessage request = new HttpRequestMessage
                {
                    Method     = HttpMethod.Get,
                    RequestUri = new Uri(url),
                };

                _log.LogTrace($"Making a GET request to {url} on behalf of subId: {subId}");

                await graphClient.AuthenticationProvider.AuthenticateRequestAsync(request); // Add authentication header

                var response = await graphClient.HttpProvider.SendAsync(request);

                string responseContent = await response.Content.ReadAsStringAsync();

                _log.LogTrace($"Recieved {responseContent} from request to {url}");

                var actualPayload = JObject.Parse(responseContent);

                // Superimpose some common properties onto the JObject for easy access.
                actualPayload["ClientState"] = entry.Subscription.ClientState;

                // Drive items only payload without resource data
                string odataType = null;
                if (notification.ResourceData != null)
                {
                    odataType = notification.ResourceData.ODataType;
                }
                else if (notification.Resource.StartsWith("/me/drive"))
                {
                    odataType = "#Microsoft.Graph.DriveItem";
                }

                actualPayload["@odata.type"] = odataType;

                var data = new WebhookTriggerData
                {
                    client    = graphClient,
                    Payload   = actualPayload,
                    odataType = odataType,
                };

                resources.Add(data);
            }

            _log.LogTrace($"Triggering {resources.Count} GraphWebhookTriggers");
            Task[] webhookReceipts = resources.Select(item => _bindingProvider.PushDataAsync(item)).ToArray();

            Task.WaitAll(webhookReceipts);
            _log.LogTrace($"Finished responding to notifications.");
        }