/// <summary> /// Read Queue for O365 Sync Folder events and write it to the database [preferably on a separate thread] /// </summary> /// <param name="queueConnection"></param> /// <returns></returns> public async System.Threading.Tasks.Task ReceiveQueueO365SyncFoldersAsync(string queueConnection) { Trace.WriteLine($"ReceiveQueueO365SyncFoldersAsync() starting"); var token = await RetreiveToken(); var EwsService = new EWService(token); var receiver = new MessageReceiver(queueConnection, SBQueueSyncO365, ReceiveMode.ReceiveAndDelete); _cancel.Token.Register(() => receiver.CloseAsync()); var filterPropertyList = new List <PropertyDefinitionBase>() { AppointmentSchema.Location, ItemSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End, AppointmentSchema.IsMeeting, AppointmentSchema.IsOnlineMeeting, AppointmentSchema.IsAllDayEvent, AppointmentSchema.IsRecurring, AppointmentSchema.IsCancelled, ItemSchema.IsUnmodified, AppointmentSchema.TimeZone, AppointmentSchema.ICalUid, ItemSchema.ParentFolderId, ItemSchema.ConversationId, AppointmentSchema.ICalRecurrenceId, EWSConstants.RefIdPropertyDef, EWSConstants.DatabaseIdPropertyDef }; // With the receiver set up, we then enter into a simple receive loop that terminates using (var EwsDatabase = new EWSDbContext(EWSConstants.Config.Database)) { // when the cancellation token if triggered. while (!_cancel.Token.IsCancellationRequested) { try { // ask for the next message "forever" or until the cancellation token is triggered var message = await receiver.ReceiveAsync(); if (message != null) { if (message.Label != null && message.ContentType != null && message.Label.Equals(SBMessageSyncO365, StringComparison.InvariantCultureIgnoreCase) && message.ContentType.Equals("application/json", StringComparison.InvariantCultureIgnoreCase)) { // service bus // #TODO: Read bus events from O365 and write to Database var booking = JsonConvert.DeserializeObject <EWS.Common.Models.ChangeBooking>(Encoding.UTF8.GetString(message.Body)); Trace.WriteLine($"Msg received: {booking.SiteMailBox} status: {booking.EventType.ToString("f")}"); var eventType = booking.EventType; var itemId = booking.ExchangeId; var changeKey = booking.ExchangeChangeKey; var appointmentMailbox = booking.SiteMailBox; try { Appointment meeting = null; var dbroom = EwsDatabase.RoomListRoomEntities.Include(idxt => idxt.Appointments).FirstOrDefault(f => f.SmtpAddress == appointmentMailbox); if (eventType == ChangeType.Delete) { var entity = dbroom.Appointments.FirstOrDefault(f => f.BookingId == itemId); entity.IsDeleted = true; entity.ModifiedDate = DateTime.UtcNow; entity.SyncedWithExchange = true; entity.ExistsInExchange = true; } else { var appointmentTime = EwsService.GetAppointment(ConnectingIdType.SmtpAddress, appointmentMailbox, itemId, filterPropertyList); if (!filterPropertyList.Any(fp => fp == AppointmentSchema.Recurrence)) { filterPropertyList.Add(AppointmentSchema.Recurrence); } var parentAppointment = EwsService.GetParentAppointment(appointmentTime, filterPropertyList); meeting = parentAppointment.Item; var mailboxId = parentAppointment.Organizer.Address; var refId = parentAppointment.ReferenceId; var meetingKey = parentAppointment.MeetingKey; // TODO: move this to the ServiceBus Processing if ((!string.IsNullOrEmpty(refId) || meetingKey.HasValue) && dbroom.Appointments.Any(f => f.BookingReference == refId || f.Id == meetingKey)) { var entity = dbroom.Appointments.FirstOrDefault(f => f.BookingReference == refId || f.Id == meetingKey); entity.EndUTC = meeting.End.ToUniversalTime(); entity.StartUTC = meeting.Start.ToUniversalTime(); entity.ExistsInExchange = true; entity.IsRecurringMeeting = meeting.IsRecurring; entity.Location = meeting.Location; entity.OrganizerSmtpAddress = mailboxId; entity.Subject = meeting.Subject; entity.RecurrencePattern = (meeting.Recurrence == null) ? string.Empty : meeting.Recurrence.ToString(); entity.BookingReference = refId; entity.BookingChangeKey = changeKey; entity.BookingId = itemId; entity.ModifiedDate = DateTime.UtcNow; entity.SyncedWithExchange = true; } else { var entity = new EntityRoomAppointment() { BookingReference = refId, BookingId = itemId, BookingChangeKey = changeKey, EndUTC = meeting.End.ToUniversalTime(), StartUTC = meeting.Start.ToUniversalTime(), ExistsInExchange = true, IsRecurringMeeting = meeting.IsRecurring, Location = meeting.Location, OrganizerSmtpAddress = mailboxId, Subject = meeting.Subject, RecurrencePattern = (meeting.Recurrence == null) ? string.Empty : meeting.Recurrence.ToString(), ModifiedDate = DateTime.UtcNow }; dbroom.Appointments.Add(entity); } } var appointmentsSaved = EwsDatabase.SaveChanges(); Trace.WriteLine($"Saved {appointmentsSaved} rows"); } catch (Exception dbex) { Trace.WriteLine($"Error occurred in Appointment creation or Database change {dbex}"); } finally { //await receiver.CompleteAsync(message.SystemProperties.LockToken); } } else { // purge / log it await receiver.DeadLetterAsync(message.SystemProperties.LockToken);//, "ProcessingError", "Don't know what to do with this message"); } } } catch (ServiceBusException e) { if (!e.IsTransient) { Trace.WriteLine(e.Message); throw; } } } } await receiver.CloseAsync(); }
/// <summary> /// Read Queue for Database Changes [preferably on a separate thread] and Store in Office 365 /// </summary> /// <param name="queueConnection"></param> /// <returns></returns> public async System.Threading.Tasks.Task ReceiveQueueDatabaseChangesAsync(string queueConnection) { var token = await RetreiveToken(); var EwsService = new EWService(token); var propertyIds = new List <PropertyDefinitionBase>() { ItemSchema.Subject, AppointmentSchema.Location, AppointmentSchema.Start, AppointmentSchema.End, EWSConstants.RefIdPropertyDef, EWSConstants.DatabaseIdPropertyDef }; var receiver = new MessageReceiver(queueConnection, SBQueueSyncDb, ReceiveMode.ReceiveAndDelete); _cancel.Token.Register(() => receiver.CloseAsync()); // when the cancellation token if triggered. while (!_cancel.Token.IsCancellationRequested) { // whatever you want to happen every 5 minutes Trace.WriteLine($"ReceiveQueueDatabaseChangesAsync({MailboxOwner}) starting at {DateTime.UtcNow.ToShortTimeString()}"); // With the receiver set up, we then enter into a simple receive loop that terminates using (var _context = new EWSDbContext(EWSConstants.Config.Database)) { try { // ask for the next message "forever" or until the cancellation token is triggered var message = await receiver.ReceiveAsync(); if (message != null) { if (message.Label != null && message.ContentType != null && message.Label.Equals(SBMessageSyncDb, StringComparison.InvariantCultureIgnoreCase) && message.ContentType.Equals("application/json", StringComparison.InvariantCultureIgnoreCase)) { // service bus // #TODO: Read bus events from database and write to O365 var booking = JsonConvert.DeserializeObject <EWS.Common.Models.UpdatedBooking>(Encoding.UTF8.GetString(message.Body)); Trace.WriteLine($"Msg received: {booking.SiteMailBox} - {booking.Subject}. Cancel status: {booking.ExchangeEvent.ToString("f")}"); var eventType = booking.CancelStatus; var eventStatus = booking.ExchangeEvent; var itemId = booking.ExchangeId; var changeKey = booking.ExchangeChangeKey; var appointmentMailbox = booking.SiteMailBox; try { Appointment meeting = null; if (!string.IsNullOrEmpty(itemId)) { var exchangeId = new ItemId(itemId); if (eventStatus == EventType.Deleted) { } else { if (string.IsNullOrEmpty(booking.BookingReference)) { booking.BookingReference = $"Ref{booking.DatabaseId.ToString().PadLeft(6, '0')}"; } EwsService.SetImpersonation(ConnectingIdType.SmtpAddress, booking.MailBoxOwnerEmail); var subAppointment = EwsService.GetAppointment(ConnectingIdType.SmtpAddress, booking.SiteMailBox, exchangeId, propertyIds); var parentAppt = EwsService.GetParentAppointment(subAppointment, propertyIds); meeting = parentAppt.Item; meeting.Subject = booking.Subject; meeting.Start = booking.StartUTC; meeting.End = booking.EndUTC; meeting.Location = booking.Location; //meeting.ReminderDueBy = DateTime.Now; meeting.SetExtendedProperty(EWSConstants.RefIdPropertyDef, booking.BookingReference); meeting.SetExtendedProperty(EWSConstants.DatabaseIdPropertyDef, booking.DatabaseId); meeting.Update(ConflictResolutionMode.AutoResolve, SendInvitationsOrCancellationsMode.SendOnlyToChanged); // Verify that the appointment was created by using the appointment's item ID. var item = Item.Bind(EwsService.Current, meeting.Id, new PropertySet(propertyIds)); Trace.WriteLine($"Appointment modified: {item.Subject} && ReserveRoomAsync({booking.Location}) completed"); if (item is Appointment) { Trace.WriteLine($"Item is Appointment"); } } } else { if (string.IsNullOrEmpty(booking.BookingReference)) { booking.BookingReference = $"Ref{booking.DatabaseId.ToString().PadLeft(6, '0')}"; } EwsService.SetImpersonation(ConnectingIdType.SmtpAddress, booking.MailBoxOwnerEmail); meeting = new Appointment(EwsService.Current); meeting.Resources.Add(booking.SiteMailBox); meeting.Subject = booking.Subject; meeting.Start = booking.StartUTC; meeting.End = booking.EndUTC; meeting.Location = booking.Location; //meeting.ReminderDueBy = DateTime.Now; meeting.SetExtendedProperty(EWSConstants.RefIdPropertyDef, booking.BookingReference); meeting.SetExtendedProperty(EWSConstants.DatabaseIdPropertyDef, booking.DatabaseId); meeting.Save(SendInvitationsMode.SendOnlyToAll); // Verify that the appointment was created by using the appointment's item ID. var item = Item.Bind(EwsService.Current, meeting.Id, new PropertySet(propertyIds)); Trace.WriteLine($"Appointment created: {item.Subject} && ReserveRoomAsync({booking.Location}) completed"); if (item is Appointment) { Trace.WriteLine($"Item is Appointment"); } } // this should exists as this particular message was sent by the database var dbAppointment = _context.AppointmentEntities.FirstOrDefault(a => a.Id == booking.DatabaseId); if (dbAppointment != null) { dbAppointment.ExistsInExchange = true; dbAppointment.SyncedWithExchange = true; dbAppointment.ModifiedDate = DateTime.UtcNow; if (meeting != null) { dbAppointment.BookingId = meeting.Id.UniqueId; dbAppointment.BookingChangeKey = meeting.Id.ChangeKey; } else { dbAppointment.IsDeleted = true; } if (string.IsNullOrEmpty(dbAppointment.BookingReference) || !dbAppointment.BookingReference.Equals(booking.BookingReference)) { dbAppointment.BookingReference = booking.BookingReference; } } var appointmentsSaved = _context.SaveChanges(); Trace.WriteLine($"Saved {appointmentsSaved} rows"); } catch (Exception dbex) { Trace.WriteLine($"Error occurred in Appointment creation or Database change {dbex}"); } finally { //await receiver.CompleteAsync(message.SystemProperties.LockToken); } } else { // purge / log it await receiver.DeadLetterAsync(message.SystemProperties.LockToken);//, "ProcessingError", "Don't know what to do with this message"); } } } catch (ServiceBusException e) { if (!e.IsTransient) { Trace.WriteLine(e.Message); throw; } } } } await receiver.CloseAsync(); }