Skip to content

Outlook event problems

Simon Brooke edited this page Apr 15, 2018 · 2 revisions

There are a number of problems in dealing with Outlook events.

We handle five classes of Outlook item event:

  1. ItemAdd
  2. ItemChange
  3. ItemRemove
  4. ItemSend
  5. NewMail

With each of these events, I am fairly confident we sometimes receive multiple events with relation to the same action on the same item. Thus when the user creates a new contact item in Outlook, we sometimes receive more than one ItemAdd event for that item. But especially in the event of the ItemChange event, while we don't quite receive one event per keystroke, we receive many ItemChange events each time an item is edited - and we don't receive a special event to indicate when the editing window is closed.

Consequently it's necessary to 'debounce' every event, and to delay transmitting updates until no new ItemChange has been received for a short period. We end up with code like this:

        /// <summary>
        /// Don't send updates immediately on change, to prevent jitter; don't send updates if nothing
        /// has really changed.
        /// </summary>
        /// <remarks>
        /// The timing logic here is legacy, and neither Andrew Forrest nor I (Simon Brooke)
        /// understand what it's intended to do; but although we've refactored it, we've left it in.
        /// </remarks>
        /// <returns>True if this item should be synced with CRM, there has been a real change,
        /// and some time has elapsed.</returns>
        internal bool ShouldPerformSyncNow()
        {
            DateTime utcNow = DateTime.UtcNow;
            double modifiedSinceSeconds = Math.Abs((utcNow - OModifiedDate).TotalSeconds);
            ILogger log = Globals.ThisAddIn.Log;
            bool reallyChanged = this.ReallyChanged();
            bool isSyncable = this.ShouldSyncWithCrm;
            string prefix = $"SyncState.ShouldPerformSyncNow: {this.CrmType} {this.CrmEntryId}";

            log.Debug(reallyChanged ? $"{prefix} has changed." : $"{prefix} has not changed.");
            log.Debug(isSyncable ? $"{prefix} is syncable." : $"{ prefix} is not syncable.");

            bool result;

            lock (this.txStateLock)
            {
                /* result is set within the lock to prevent one thread capturing another thread's
                 * state change. */
                result = isSyncable && reallyChanged && this.TxState == TransmissionState.Pending && modifiedSinceSeconds > 2;
                if (result)
                {
                    this.OModifiedDate = utcNow;
                }
            }

            log.Debug(this.TxState == TransmissionState.Pending ? $"{prefix} is recently updated" : $"{prefix} is not recently updated");

            log.Debug(result ? $"{prefix} should be synced now" : $"{prefix} should not be synced now");

            return result;
        }

Thoughts about handling Outlook events in Version 4

It occurs to me that we probably don't have to handle the ItemAdded event at all, and that that will make life a very great deal easier. Every item that is added must inevitably immediately be changed. This also means that when bringing a new item in from CRM, we can instantiate the Wrapper before creating the Outlook object. That way, we can avoid much complicated code.

It also would mean that the transition to NewFromCRM would come only from New, which would make the State Transition Engine more robust.