public ActionResult Index(string mode = "all", int page = 1) { List <StructurePostToRender> lst = new List <StructurePostToRender>(); EWSDbContext db = new EWSDbContext(); ViewBag.userId = Session["uid"]; ViewBag.userName = Session["uname"]; ViewBag.ufacultyid = Session["ufacultyid"]; ViewBag.uroleid = Session["uroleid"]; ViewBag.facultyname = Session["facultyname"]; ViewBag.opentime = Session["opentime"]; int pageSize = 5; int rowCount = (from s in db.Posts where s.isActive == true select s).Count(); int pageCount = rowCount / pageSize; ViewBag.pageCount = rowCount / pageSize; //ViewBag.pageSize = pageSize; ViewBag.pageCur = page; //ViewBag.mode = mode; if (rowCount % pageSize > 0) { ViewBag.pageCount = rowCount / pageSize + 1; pageCount = rowCount / pageSize + 1; } if (page > pageCount) { page = pageCount; } if (page <= 0) { page = 1; } int roleid_temp = Int32.Parse(Session["uroleid"].ToString()); int facultyid_temp = Int32.Parse(Session["ufacultyid"].ToString()); if (roleid_temp == 1 || roleid_temp == 5) { lst = PostBLL.Post_GetAllPost_Guest(page, pageSize); } else { if (mode == "all") { lst = PostBLL.Post_GetAllPost(page, pageSize, Int32.Parse(Session["ufacultyid"].ToString())); } if (mode == "popular") { lst = PostBLL.Post_GetTopPopularPost(facultyid_temp); } if (mode == "topview") { lst = PostBLL.Post_GetTopViewPost(facultyid_temp); } } return(View(lst)); }
/// <summary> /// Reconnect StreamingSubscriptionConnections [if not in a disconnecting or error'd state] /// </summary> public void ReconnectToSubscriptions() { // Go through our connections and reconnect any that have closed _reconnect = false; lock (_reconnectLock) // Prevent this code being run concurrently (i.e. if an event fires in the middle of the processing) { using (EWSDbContext context = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var _connectionPair in _connections) { var connectionGroupName = _connectionPair.Key; var groupInfo = _groups[connectionGroupName]; var _connection = _connections[connectionGroupName]; if (!_connection.IsOpen) { try { try { _connection.Open(); _traceListener.Trace("SyncProgram", $"Re-opened connection for group {connectionGroupName}"); } catch (Exception ex) { if (ex.Message.StartsWith("You must add at least one subscription to this connection before it can be opened")) { // Try recreating this group AddGroupSubscriptions(context, connectionGroupName); } else { _traceListener.Trace("SyncProgram", $"Failed to reopen connection: {ex.Message}"); } } } catch (Exception ex) { _traceListener.Trace("SyncProgram", $"Failed to reopen connection: {ex.Message}"); } } } } } }
/// <summary> /// Adds streamingsubscription to the GroupInfo /// </summary> /// <param name="context">Database context</param> /// <param name="Group"></param> /// <param name="smtpAddress"></param> /// <returns></returns> private StreamingSubscription AddSubscription(EWSDbContext context, GroupInfo Group, string smtpAddress) { StreamingSubscription subscription = null; if (_subscriptions.Any(email => email.SmtpAddress.Equals(smtpAddress))) { var email = _subscriptions.FirstOrDefault(s => s.SmtpAddress.Equals(smtpAddress)); _subscriptions.Remove(email); } try { ExchangeService exchange = Group.ExchangeService; exchange.Credentials = ServiceCredentials; exchange.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, smtpAddress); subscription = exchange.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.Calendar }, EventType.Created, EventType.Deleted, EventType.Modified, EventType.Moved, EventType.Copied); _traceListener.Trace("SyncProgram", $"CreateStreamingSubscriptionGrouping to room {smtpAddress} with SubscriptionId {subscription.Id}"); var subscriptions = context.SaveChanges(); _traceListener.Trace("SyncProgram", $"Streaming subscription persisted {subscriptions} persisted."); _subscriptions.Add(new SubscriptionCollection() { SmtpAddress = smtpAddress, Streaming = subscription }); } catch (Microsoft.Exchange.WebServices.Data.ServiceRequestException srex) { _traceListener.Trace("SyncProgram", $"Failed to provision subscription {srex.Message}"); throw new Exception($"Subscription could not be created for {smtpAddress} with MSG:{srex.Message}"); } return(subscription); }
public ActionResult Index(string mode = "all", int page = 1) { List <StructurePostToRender> lst = new List <StructurePostToRender>(); EWSDbContext db = new EWSDbContext(); int pageSize = 5; int rowCount = (from s in db.Posts select s).Count(); int pageCount = rowCount / pageSize; ViewBag.pageCount = rowCount / pageSize; //ViewBag.pageSize = pageSize; ViewBag.pageCur = page; //ViewBag.mode = mode; ViewBag.userId = Session["uid"]; ViewBag.userName = Session["uname"]; ViewBag.ufacultyid = Session["ufacultyid"]; ViewBag.uroleid = Session["uroleid"]; if (rowCount % pageSize > 0) { ViewBag.pageCount = rowCount / pageSize + 1; pageCount = rowCount / pageSize + 1; } if (page > pageCount) { page = pageCount; } if (page <= 0) { page = 1; } if (mode == "all") { lst = PostBLL.Post_GetAllPost(page, pageSize); } if (mode == "popular") { lst = PostBLL.Post_GetTopPopularPost(); } if (mode == "topview") { lst = PostBLL.Post_GetTopViewPost(); } return(View(lst)); }
/// <summary> /// Close connections and unsubscribe /// </summary> public void CloseConnections() { _traceListener.Trace("SyncProgram", $"ConsoleCtrlCheck CloseConnections at {DateTime.UtcNow}.."); foreach (StreamingSubscriptionConnection connection in _connections.Values) { if (connection.IsOpen) { connection.Close(); } } // Unsubscribe all if (_subscriptions == null) { return; } using (EWSDbContext context = new EWSDbContext(EWSConstants.Config.Database)) { var databaseItems = context.RoomListRoomEntities.ToList(); try { for (int i = _subscriptions.Count - 1; i >= 0; i--) { SubscriptionCollection subscriptionItem = _subscriptions[i]; var subscription = subscriptionItem.Streaming; try { subscription.Unsubscribe(); _traceListener.Trace("SyncProgram", $"Unsubscribed from {subscriptionItem.SmtpAddress}"); if (databaseItems.Any(di => di.SmtpAddress == subscriptionItem.SmtpAddress)) { var item = databaseItems.FirstOrDefault(di => di.SmtpAddress == subscriptionItem.SmtpAddress); item.LastSyncDate = DateTime.UtcNow; } } catch (Exception ex) { _traceListener.Trace("SyncProgram", $"Error when unsubscribing {subscriptionItem.SmtpAddress}: {ex.Message}"); } _subscriptions.Remove(subscriptionItem); } } catch (Exception subEx) { _traceListener.Trace("SyncProgram", $"Failed in subscription disconnect {subEx.Message}"); } finally { var changes = context.SaveChanges(); _traceListener.Trace("SyncProgram", $"Subscription watermark sync changed {changes} rows."); } } _reconnect = false; }
/// <summary> /// Process the GroupInfo and create subscriptions based on AnchorMailbox /// </summary> /// <param name="context">Database context for subscription update</param> /// <param name="groupName">EWS GroupInfo or Dynamic Groupname if Mailboxes > 200</param> /// <returns></returns> public bool AddGroupSubscriptions(EWSDbContext context, string groupName) { if (!_groups.ContainsKey(groupName)) { return(false); } if (_connections == null) { _connections = new Dictionary <string, StreamingSubscriptionConnection>(); } if (_connections.ContainsKey(groupName)) { var _connection = _connections[groupName]; foreach (StreamingSubscription subscription in _connection.CurrentSubscriptions) { try { subscription.Unsubscribe(); } catch { } } try { _connection.Close(); _groups[groupName].IsConnectionOpen = false; } catch { } } try { // Create the connection for this group, and the primary mailbox subscription var groupInfo = _groups[groupName]; var PrimaryMailbox = groupInfo.PrimaryMailbox; // Return the subscription, or create a new one if we don't already have one StreamingSubscription mailboxSubscription = AddSubscription(context, groupInfo, PrimaryMailbox); if (_connections.ContainsKey(groupName)) { _connections[groupName] = new StreamingSubscriptionConnection(mailboxSubscription.Service, pollingTimeout); } else { _connections.Add(groupName, new StreamingSubscriptionConnection(mailboxSubscription.Service, pollingTimeout)); } SubscribeConnectionEvents(_connections[groupName]); _connections[groupName].AddSubscription(mailboxSubscription); _traceListener.Trace("SyncProgram", $"{PrimaryMailbox} (primary mailbox) subscription created in group {groupName}"); // Now add any further subscriptions in this group foreach (string sMailbox in groupInfo.Mailboxes.Where(w => !w.Equals(PrimaryMailbox))) { try { var localSubscription = AddSubscription(context, groupInfo, sMailbox); _connections[groupName].AddSubscription(localSubscription); _traceListener.Trace("Add secondary subscription", $"{sMailbox} subscription created in group {groupName}"); } catch (Exception ex) { _traceListener.Trace("Exception", $"ERROR when subscribing {sMailbox} in group {groupName}: {ex.Message}"); } } } catch (Exception ex) { _traceListener.Trace("Exception", $"ERROR when creating subscription connection group {groupName}: {ex.Message}"); } return(true); }
/// <summary> /// Enable the synchronization of individual folders or Room[s] /// </summary> /// <param name="folderInfo"></param> public void ProcessChanges(EWSFolderInfo folderInfo) { bool moreChangesAvailable = false; _traceListener.Trace("SyncProgram", $"Entered ProcessChanges for {folderInfo.SmtpAddress} at {DateTime.UtcNow}"); using (EWSDbContext context = new EWSDbContext(EWSConstants.Config.Database)) { var room = context.RoomListRoomEntities.FirstOrDefault(f => f.SmtpAddress.Equals(folderInfo.SmtpAddress)); var email = room.SmtpAddress; var syncState = room.SynchronizationState; var syncTimestamp = room.SynchronizationTimestamp; try { do { // Get all changes since the last call. The synchronization cookie is stored in the _SynchronizationState field. _traceListener.Trace("SyncProgram", $"Sync changes {email} with timestamp {syncTimestamp}"); // Just get the IDs of the items. // For performance reasons, do not use the PropertySet.FirstClassProperties. var changes = folderInfo.Service.Current.SyncFolderItems(folderInfo.Folder, PropertySet.IdOnly, null, 512, SyncFolderItemsScope.NormalItems, syncState); // Update the synchronization syncState = changes.SyncState; // Process all changes. If required, add a GetItem call here to request additional properties. foreach (ItemChange itemChange in changes) { // This example just prints the ChangeType and ItemId to the console. // A LOB application would apply business rules to each _traceListener.Trace("SyncProgram", $"ChangeType = {itemChange.ChangeType} with ItemId {itemChange.ItemId.ToString()}"); // Send an item event you can bind to var service = System.Threading.Tasks.Task.Run(async() => { _traceListener.Trace("SyncProgram", "In Thread run await...."); await Messenger.SendQueueO365SyncFoldersAsync(queueSync, email, itemChange); }, CancellationTokenSource.Token); service.Wait(); } // If more changes are available, issue additional SyncFolderItems requests. moreChangesAvailable = changes.MoreChangesAvailable; room.SynchronizationState = syncState; room.SynchronizationTimestamp = DateTime.UtcNow; var roomchanges = context.SaveChanges(); _traceListener.Trace("SyncProgram", $"Room event folder sync {roomchanges} persisted."); }while (moreChangesAvailable); } catch (Exception processEx) { Trace.TraceError($"Failed to send queue {processEx.Message}"); } finally { room.SynchronizationState = syncState; room.SynchronizationTimestamp = DateTime.UtcNow; var roomchanges = context.SaveChanges(); _traceListener.Trace("SyncProgram", $"Failed ProcessChanges({email}) folder sync {roomchanges} persisted."); } } }
/// <summary> /// Creates pull subscriptions for all rooms and waits on timer delay to pull subscriptions /// </summary> /// <param name="mailboxOwner"></param> /// <returns></returns> private async System.Threading.Tasks.Task PullSubscriptionChangesAsync(string mailboxOwner) { _traceListener.Trace("SyncProgram", $"PullSubscriptionChangesAsync({mailboxOwner}) starting"); var service = new EWService(EwsToken); service.SetImpersonation(ConnectingIdType.SmtpAddress, mailboxOwner); if (_subscriptions == null) { _subscriptions = new List <SubscriptionCollection>(); } var EwsService = new EWService(EwsToken); EwsService.SetImpersonation(ConnectingIdType.SmtpAddress, mailboxOwner); // Retreive and Store PullSubscription Details using (var _context = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var room in _context.RoomListRoomEntities.Where(w => !string.IsNullOrEmpty(w.Identity))) { EntitySubscription dbSubscription = null; string watermark = null; if (_context.SubscriptionEntities.Any(rs => rs.SmtpAddress == room.SmtpAddress)) { dbSubscription = _context.SubscriptionEntities.FirstOrDefault(rs => rs.SmtpAddress == room.SmtpAddress); watermark = dbSubscription.Watermark; } else { // newup a subscription to track the watermark dbSubscription = new EntitySubscription() { LastRunTime = DateTime.UtcNow, SmtpAddress = room.SmtpAddress }; _context.SubscriptionEntities.Add(dbSubscription); } try { var roomService = new EWService(EwsToken); var subscription = roomService.CreatePullSubscription(ConnectingIdType.SmtpAddress, room.SmtpAddress, pollingTimeout, watermark); // close out the old subscription dbSubscription.PreviousWatermark = (!string.IsNullOrEmpty(watermark)) ? watermark : null; dbSubscription.Watermark = subscription.Watermark; _traceListener.Trace("SyncProgram", $"ListenToRoomReservationChangesAsync.Subscribed to room {room.SmtpAddress}"); _subscriptions.Add(new SubscriptionCollection() { Pulling = subscription, SmtpAddress = room.SmtpAddress }); var rowChanged = _context.SaveChanges(); _traceListener.Trace("SyncProgram", $"Pull subscription persisted {rowChanged} rows"); } catch (Microsoft.Exchange.WebServices.Data.ServiceRequestException srex) { _traceListener.Trace("SyncProgram", $"Failed to provision subscription {srex.Message}"); throw new Exception($"Subscription could not be created for {room.SmtpAddress} with MSG:{srex.Message}"); } } } try { var waitTimer = new TimeSpan(0, 5, 0); while (!CancellationTokenSource.IsCancellationRequested) { var milliseconds = (int)waitTimer.TotalMilliseconds; using (var _context = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var item in _subscriptions) { bool?ismore = default(bool); do { PullSubscription subscription = item.Pulling; var events = subscription.GetEvents(); var watermark = subscription.Watermark; ismore = subscription.MoreEventsAvailable; var email = item.SmtpAddress; var databaseItem = _context.SubscriptionEntities.FirstOrDefault(rs => rs.SmtpAddress == email); // pull last event from stack TODO: need heuristic for how meetings can be stored var filteredEvents = events.ItemEvents.OrderBy(x => x.TimeStamp); foreach (ItemEvent ev in filteredEvents) { var itemId = ev.ItemId; try { // Send an item event you can bind to await Messenger.SendQueueO365ChangesAsync(queueSubscription, email, ev); } catch (ServiceResponseException ex) { _traceListener.Trace("SyncProgram", $"ServiceException: {ex.Message}"); continue; } } databaseItem.Watermark = watermark; databaseItem.LastRunTime = DateTime.UtcNow; // Save Database changes await _context.SaveChangesAsync(); }while (ismore == true); } } _traceListener.Trace("SyncProgram", $"Sleeping at {DateTime.UtcNow} for {milliseconds} milliseconds..."); System.Threading.Thread.Sleep(milliseconds); } } catch (Exception ex) { Console.WriteLine(ex.Message); } _traceListener.Trace("SyncProgram", $"PullSubscriptionChangesAsync({mailboxOwner}) exiting"); }
/// <summary> /// Creates grouping subscriptions and waits for the notification events to flow /// </summary> /// <param name="impersonationId"></param> /// <returns></returns> async public System.Threading.Tasks.Task CreateStreamingSubscriptionGroupingAsync(string impersonationId) { var database = EWSConstants.Config.Database; using (EWSDbContext context = new EWSDbContext(database)) { var smtpAddresses = await context.RoomListRoomEntities.ToListAsync(); foreach (var sMailbox in smtpAddresses) { var addedBox = _mailboxes.AddMailbox(sMailbox.SmtpAddress); if (!addedBox) { _traceListener.Trace("SyncProgram", $"Failed to add SMTP {sMailbox.SmtpAddress}"); } MailboxInfo mailboxInfo = _mailboxes.Mailbox(sMailbox.SmtpAddress); if (mailboxInfo != null) { GroupInfo groupInfo = null; if (_groups.ContainsKey(mailboxInfo.GroupName)) { groupInfo = _groups[mailboxInfo.GroupName]; } else { groupInfo = new GroupInfo(mailboxInfo.GroupName, mailboxInfo.SMTPAddress, mailboxInfo.EwsUrl, EwsToken, _traceListener); _groups.Add(mailboxInfo.GroupName, groupInfo); } if (groupInfo.Mailboxes.Count > 199) { // We already have enough mailboxes in this group, so we rename it and create a new one // Renaming it means that we can still put new mailboxes into the correct group based on GroupingInformation int i = 1; while (_groups.ContainsKey($"{groupInfo.Name}-{i}")) { i++; } // Remove previous grouping name from stack _groups.Remove(groupInfo.Name); // Add the grouping back with the new grouping name [keep the GroupInfo with previous name] _groups.Add($"{groupInfo.Name}-{i}", groupInfo); // Provision a new GroupInfo with the GroupName groupInfo = new GroupInfo(mailboxInfo.GroupName, mailboxInfo.SMTPAddress, mailboxInfo.EwsUrl, EwsToken, _traceListener); // Add GroupInfo to stack _groups.Add(mailboxInfo.GroupName, groupInfo); } // Add the mailbox to the collection groupInfo.Mailboxes.Add(sMailbox.SmtpAddress); } } // Enable the Grouping foreach (var _group in _groups) { _traceListener.Trace("SyncProgram", $"Opening connections for {_group.Key}"); var groupName = _group.Key; var groupInfo = _group.Value; // Create a streaming connection to the service object, over which events are returned to the client. // Keep the streaming connection open for 30 minutes. if (AddGroupSubscriptions(context, groupName)) { _traceListener.Trace("SyncProgram", $"{groupInfo.Mailboxes.Count()} mailboxes primed for StreamingSubscriptions."); } else { _traceListener.Trace("SyncProgram", $"Group {groupInfo.Name} failed in StreamingSubscription events."); } } } using (var semaphore = new System.Threading.SemaphoreSlim(1)) { // Block the Thread semaphore.Wait(); // Establish the StreamingSubscriptionConnections based on the GroupingInfo foreach (var connection in _connections) { var _group = _groups[connection.Key]; var _connection = connection.Value; if (_connection.IsOpen) { _group.IsConnectionOpen = true; return; } try { _connection.Open(); _group.IsConnectionOpen = true; } catch (Exception ex) { _traceListener.Trace("SyncProgram", $"Error opening streamingsubscriptionconnection for group {_group.Name} MSG {ex.Message}"); } } // Lock the Thread Until its cancelled or fails await semaphore.WaitAsync(CancellationTokenSource.Token); } }
/// <summary> /// Establish the connection /// </summary> /// <returns></returns> async private System.Threading.Tasks.Task RunAsync() { _traceListener = new ClassTraceListener(); IsDisposed = false; EwsToken = await EWSConstants.AcquireTokenAsync(); Messenger = new MessageManager(CancellationTokenSource); ServiceCredentials = new OAuthCredentials(EwsToken.AccessToken); _reconnect = true; _groups = new Dictionary <string, GroupInfo>(); _mailboxes = new Mailboxes(ServiceCredentials, _traceListener); _subscriptions = new List <SubscriptionCollection>(); _connections = new Dictionary <string, StreamingSubscriptionConnection>(); var impersonationId = EWSConstants.Config.Exchange.ImpersonationAcct; try { var list = new List <EWSFolderInfo>(); using (EWSDbContext context = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var room in context.RoomListRoomEntities.Where(w => !string.IsNullOrEmpty(w.Identity))) { var mailboxId = room.SmtpAddress; try { var roomService = new EWService(EwsToken); roomService.SetImpersonation(ConnectingIdType.SmtpAddress, mailboxId); var folderId = new FolderId(WellKnownFolderName.Calendar, mailboxId); var info = new EWSFolderInfo() { SmtpAddress = mailboxId, Service = roomService, Folder = folderId }; list.Add(info); } catch (Exception srex) { _traceListener.Trace("SyncProgram", $"Failed to ProcessChanges{srex.Message}"); throw new Exception($"ProcessChanges for {mailboxId} with MSG:{srex.Message}"); } } } // Parallel ForEach (on RoomMailbox Grouping and SyncFolders) await System.Threading.Tasks.Task.Run(() => { ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = maxConcurrency }; // Fireoff folder sync in background thread Parallel.ForEach(list, options, (bodyInfo) => { ProcessChanges(bodyInfo); }); }); var tasks = new List <System.Threading.Tasks.Task>(); if (EWSConstants.Config.Exchange.PullEnabled) { // Upon completion tick repeater to poll subscriptions tasks.Add(PullSubscriptionChangesAsync(impersonationId)); } else { // Upon completion kick of streamingsubscription tasks.Add(CreateStreamingSubscriptionGroupingAsync(impersonationId)); } System.Threading.Tasks.Task.WaitAll(tasks.ToArray()); } catch (Exception ex) { Trace.TraceError(ex.Message); } }
/// <summary> /// Poll localDB events and push service bus events to the Queue /// </summary> /// <param name="queueConnection"></param> /// <returns></returns> public async System.Threading.Tasks.Task SendQueueDatabaseChangesAsync(string queueConnection) { var sender = new MessageSender(queueConnection, SBQueueSyncDb); var token = await RetreiveToken(); var EwsService = new EWService(token); EwsService.SetImpersonation(ConnectingIdType.SmtpAddress, MailboxOwner); // Poll the rooms to store locally var roomlisting = EwsService.GetRoomListing(); using (var EwsDatabase = new EWSDbContext(EWSConstants.Config.Database)) { foreach (var roomlist in roomlisting) { foreach (var room in roomlist.Value) { EntityRoomListRoom databaseRoom = null; if (EwsDatabase.RoomListRoomEntities.Any(s => s.SmtpAddress == room.Address)) { databaseRoom = await EwsDatabase.RoomListRoomEntities.FirstOrDefaultAsync(f => f.SmtpAddress == room.Address); } else { databaseRoom = new EntityRoomListRoom() { SmtpAddress = room.Address, Identity = room.Address, RoomList = roomlist.Key }; EwsDatabase.RoomListRoomEntities.Add(databaseRoom); } } } var roomchanges = await EwsDatabase.SaveChangesAsync(); Trace.WriteLine($"Rooms {roomchanges} saved to database."); } var waitTimer = new TimeSpan(0, 5, 0); while (!_cancel.IsCancellationRequested) { var milliseconds = (int)waitTimer.TotalMilliseconds; // whatever you want to happen every 5 minutes Trace.WriteLine($"SendQueueDatabaseChangesAsync({MailboxOwner}) starting at {DateTime.UtcNow.ToShortTimeString()}"); using (var EwsDatabase = new EWSDbContext(EWSConstants.Config.Database)) { var i = 0; var bookings = EwsDatabase.AppointmentEntities.Include(ictx => ictx.Room) .Where(w => !w.ExistsInExchange || !w.SyncedWithExchange || (w.DeletedLocally && !w.SyncedWithExchange)); foreach (var booking in bookings) { Microsoft.Exchange.WebServices.Data.EventType eventType = Microsoft.Exchange.WebServices.Data.EventType.Deleted; if (!booking.ExistsInExchange) { eventType = Microsoft.Exchange.WebServices.Data.EventType.Created; } else if (!booking.SyncedWithExchange) { eventType = Microsoft.Exchange.WebServices.Data.EventType.Modified; } if (string.IsNullOrEmpty(booking.BookingReference)) { booking.BookingReference = $"Ref{booking.Id.ToString().PadLeft(6, '0')}"; } var ewsbooking = new EWS.Common.Models.UpdatedBooking() { DatabaseId = booking.Id, MailBoxOwnerEmail = booking.OrganizerSmtpAddress, SiteMailBox = booking.Room.SmtpAddress, Subject = booking.Subject, Location = booking.Location, StartUTC = booking.StartUTC, EndUTC = booking.EndUTC, ExchangeId = booking.BookingId, ExchangeChangeKey = booking.BookingChangeKey, BookingReference = booking.BookingReference, ExchangeEvent = eventType }; var message = new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(ewsbooking))) { ContentType = "application/json", Label = SBMessageSyncDb, MessageId = i.ToString() }; await sender.SendAsync(message); Trace.WriteLine($"{++i}. Sent: Id = {message.MessageId} w/ Subject:{booking.Subject}"); } Trace.WriteLine($"Sent {i} messages"); } Trace.WriteLine($"Sleeping at {DateTime.UtcNow} for {milliseconds} milliseconds..."); System.Threading.Thread.Sleep(milliseconds); } }
/// <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(); }