Not able to delete subscription but keep receving notifications

Rexhi Neziri 1 Reputation point
2021-06-07T15:03:46.297+00:00

CONTEXT
Normally i can create and delete subscriptions but for some reasons a few subscriptions keep sending me notifications with an id subscription but when i'm running the request i have an error and notifications keep coming.
I'm using ngrok to receve notifications locally so nothing is on prod.

The user id on the notification information is the same as the one i use on my application, also the event is no more on my calendar and the resource data is the correct one.

Here 2 exemples of the information on the notification

ChangeType [string]:"deleted"
ClientState [string]:"grp_test53///test_cv_2"
Resource [string]:"Users/myid/Events/myidevent"
ResourceData:myresource
SubscriptionExpirationDateTime [DateTimeOffset]:{08.06.2021 09:30:00 -07:00}
SubscriptionId [string]:"deb7f7d1-b4eb-4a94-ad7e-575c578c24c5"

ChangeType [string]:"updated"
ClientState [string]:"grp_test49///test_cv_2"
Resource [string]:"Users/myid/Events/myidevent"
ResourceData:myresource
SubscriptionExpirationDateTime [DateTimeOffset]:{08.06.2021 09:30:00 -07:00}
SubscriptionId [string]:"d90e3abd-8e79-49bb-b8ac-09bde567579b"

ERROR
This is the error when i try to delete the subscription

'Code: ResourceNotFound
Message: The object was not found.
Inner error
AdditionalData:
date: 2021-06-07T14:45:07
request-id: 7dd7ec29-64f7-4f5e-a002-222a7318d421
client-request-id: 7dd7ec29-64f7-4f5e-a002-222a7318d421
ClientRequestId: 7dd7ec29-64f7-4f5e-a002-222a7318d421'

PROBLEM
I'm not able to delete this notifications

*EDIT
After some test and research i have understand something:

Each time i'm creating an event i'm also creating a subscription to the calendar, that mean i'm creating multiple subscriptions for the same calendar, that's wrong!

SOLUTION

When creating an event i need to check if a subscription already existe for the calendar of the event, maybe update the expiration time but that all.

Hope this helps other people who had misunderstand like me how subscription works.

Here the code to do so.

public async Task CreateSessionAsync(ISession session, string emailUser)
        {
            logger.LogDebug("CreateSession Teams by '{0}': course '{1}', group id '{2}', name '{3}', tutor '{4}', date '{5}', duration '{6}'",
                    emailUser, session.CodeStage, session.CodeGroupe, session.SessionName, session.IdTutor, session.DateSession, session.Duration);

            config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
            // Init the provider
            GraphHelper.Initialize();

            var organizer = await GraphHelper.GetUserAsync(emailUser);

            var reponseCalendar = await GraphHelper.GetCalendarAsync(emailUser);

            var @event = new Event
            {
                Subject = session.SessionName,
                Start = new DateTimeTimeZone
                {
                    DateTime = session.DateSession.ToString("yyyy-MM-ddTHH:mm"),
                    TimeZone = "UTC"
                },
                End = new DateTimeTimeZone
                {
                    DateTime = session.DateSession.AddMinutes(session.Duration).ToString("yyyy-MM-ddTHH:mm"),
                    TimeZone = "UTC"
                },
                Attendees = new List<Attendee>()
                {
                    new Attendee
                    {
                        EmailAddress = new EmailAddress
                            {
                                Address = emailUser,
                                Name = organizer.DisplayName
                            },
                    Type = AttendeeType.Required
                    }
                },
                Organizer = new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = emailUser,
                        Name = organizer.DisplayName
                    },

                },
                IsOrganizer = true,
                IsOnlineMeeting = true,
                OnlineMeetingProvider = OnlineMeetingProviderType.TeamsForBusiness,
                TransactionId = session.CodeGroupe + "{}" + session.CodeStage + "{$}"

            };

            var reponseEvent = await GraphHelper.CreateEventAsync(emailUser, @event, reponseCalendar.Id);

            logger.LogDebug("CREATE SESSION, create TransactionId : " + reponseEvent.TransactionId);

            var allSubscriptions = await GraphHelper.GetAllSubscriptionsAsync();
            var needToCreateSubscription = true;
            foreach (var sub in allSubscriptions)
            {
                var graphUserId = sub.Resource.Split("/")[1];
                var calendarTeamsId = sub.Resource.Split("/")[3];
                if (calendarTeamsId == reponseCalendar.Id && graphUserId == organizer.Id)
                {
                    // subscription for this calendar already exist
                    needToCreateSubscription = false;
                    sub.ClientState += reponseEvent.TransactionId;

                    await GraphHelper.UpdateSubscriptionAsync(sub);
                }
                else
                {
                    // we do nothing
                }
            }
            if (needToCreateSubscription)
            {
                var sessionEndDate = session.DateSession.AddMinutes(session.Duration).AddHours(2); // TIME IS UTC FORMAT, SO ADD 2 HOURS

                var limitSubscriptionDate = DateTime.Now.AddMinutes(4230); // max 4230 minutes

                if (sessionEndDate < limitSubscriptionDate)
                {
                    limitSubscriptionDate = sessionEndDate;
                }
                else
                {
                    // limitSubscriptionDate is the date to use for the expiration time of subscription
                }

                // for local use : ngrok http https://localhost:5001
                var subscription = new Subscription
                {
                    ChangeType = "updated,deleted",
                    NotificationUrl = config.UrlSubscriptionGraph + "notifications",
                    Resource = "users/" + organizer.Id + "/calendars/" + reponseCalendar.Id + "/events",
                    ExpirationDateTime = limitSubscriptionDate,
                    ClientState = reponseEvent.TransactionId
                };

                var reponseSub = await GraphHelper.CreateSubscriptionAsync(subscription);

                logger.LogDebug("CREATE SUBSCRIPTION, create subscriptionId, expire on : " + reponseSub.ExpirationDateTime);

                var infoSub = "subcriptionId:" + reponseSub.Id;

                try
                {
                    var existeSubscription = await this.VCRdbContext.Set<TeamsSubscription>()
                                   .FirstOrDefaultAsync((ts) => ts.SubcriptionId == reponseSub.Id);
                    if (existeSubscription == null)
                    {
                        await this.VCRdbContext.Set<TeamsSubscription>().AddAsync(new TeamsSubscription
                        {
                            SubcriptionId = reponseSub.Id,
                            CalendarId = reponseCalendar.Id,
                            GraphUserId = organizer.Id,
                            ExpirationDateTime = limitSubscriptionDate
                        });

                        await this.VCRdbContext.SaveChangesAsync();
                        logger.LogDebug("ADDED SUBSCRIPTION TO DB, " + infoSub);
                    }
                    else
                    {
                        // Already in the DB
                    }
                }
                catch (Exception ex)
                {
                    this.logger.LogWarning($"Error on ADDING SUBSCRIPTION TO DB : {ex.Message}");
                }
            }
            else
            {
                // we do nothing, subscription for this calendar already exist
            }
        }

Have a great day

Bye

Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
13,499 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.