Fun with Exchange 2007 Push Notifications
Now, you would think this should be pretty straight forward by now. But it's not.
Scenario: I am subscribed to a users calendar as follows:
BaseFolderIdType[] folders = new BaseFolderIdType[1];
DistinguishedFolderIdType folderId = new DistinguishedFolderIdType();
folderId.Id = DistinguishedFolderIdNameType.calendar;
folders[0] = folderId;
pushSubscription.FolderIds = folders;
// Subscribe to all events.
NotificationEventTypeType[] eventTypes = new NotificationEventTypeType[5];
eventTypes[0] = NotificationEventTypeType.CopiedEvent;
eventTypes[1] = NotificationEventTypeType.CreatedEvent;
eventTypes[2] = NotificationEventTypeType.DeletedEvent;
eventTypes[3] = NotificationEventTypeType.ModifiedEvent;
eventTypes[4] = NotificationEventTypeType.MovedEvent;
pushSubscription.EventTypes = eventTypes;
In the notification function, I check as follows for each item I am notified of as per PushNotificationClient.cs in the SDK:
int i = 0;
// Cast the notification event to the proper type
foreach (BaseNotificationEventType bnet in notification.Items)
{
// Get the event name
string eventName = notification.ItemsElementName[i].ToString();
BaseObjectChangedEventType it = bnet as BaseObjectChangedEventType;
if (it == null)
{
continue;
}
if (!(it.Item is ItemIdType))
{
continue;
}
// Code to display details about the event
ItemIdType item = it.Item as ItemIdType;
Debug.WriteLine(eventName.PadRight(20) + "[" + (bnet.GetType().ToString() + "]:").PadLeft(35, ' ') + item.Id + "\t\t" + item.ChangeKey);
Now, you would think that when you create an appointment, you would get a CreatedEvent,
when you do a permanent delete you would get a DeletedEvent, and so on. But this is what you really get:
| ===== OWA ===== |
| CREATE |
| ModifiedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5RAAriVlgoAAA | AAAAAA== |
| IPM.Appointment: fghfhdfghdfghdfgh
|
| EXPANDED / CONTRACT / MOVE WITHIN CALENDAR |
| ModifiedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5RAAriVlgpQAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| CreatedEvent | [ModifiedEventType] | RAAQUKzDsAAA5RAAriVlgoQAA | DwAAAA== |
| IPM.Appointment: fghfhdfghdfghdfgh |
| ModifiedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5RAAriVlgpQAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| SOFT DELETE |
| ModifiedEvent | [MovedCopiedEventType] | RAAQUK0ABgAA5RAAriVlwzQAA | AAAAAA== |
| IPM.Appointment: fghfhdfghdfghdfgh |
| === OUTLOOK === |
| CREATE |
| ModifiedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgEAwAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| EXPANDED / CONTRACT / MOVE WITHIN CALENDAR |
| ModifiedEvent | [ModifiedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgEAwAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| MOVED FOLDER / SOFT DELETE / SOFT DELETE RESTORE |
| ModifiedEvent | [MovedCopiedEventType] | eAAriVgADAAA5jp9kS9UdUCKFiIaz2NQeAAriVgSAQAA | AAAAAA== |
| IPM.Appointment: TEST 5 |
| COPIED WITHIN CALENDAR |
| ModifiedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgEBAAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| HARD DELETE |
| ModifiedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgEBAAA | DwAAAA== |
| No Messages Matched: ErrorItemNotFound |
Not exactly sensible. but I think I've found the problem.
for (int i = 0;i < notification.Items.Length; i++)
{
BaseNotificationEventType bnet = notification.Items[i];
// Get the event name
string eventName = notification.ItemsElementName[i].ToString();
BaseObjectChangedEventType it = bnet as BaseObjectChangedEventType;
if (it == null)
{
continue;
}
if (!(it.Item is ItemIdType))
{
continue;
}
// Code to display details about the event
ItemIdType item = it.Item as ItemIdType;
Debug.WriteLine(eventName.PadRight(20) + "[" + (bnet.GetType().ToString() + "]:").PadLeft(35, ' ') + item.Id + "\t\t" + item.ChangeKey);
If you replace the foreach with a for loop instead, so you can make sure the item and the event name line up, you get:
| ===== OWA ===== |
| CREATE |
| CreatedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2JgAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| CreatedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2JwAA | DwAAAA== |
| IPM.Appointment: TEST 6 |
| DeletedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2JgAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| EXPANDED / CONTRACT / MOVE WITHIN CALENDAR |
| CreatedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2KAAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| ModifiedEvent | [ModifiedEventType] | GRlvYJ3GL/RAArjVW2JwAA | DwAAAA== |
| IPM.Appointment: TEST 6 |
| DeletedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2KAAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| SOFT DELETE |
| MovedEvent | [MovedCopiedEventType] | GRlvYJ3GL/RAArjVXWTQAA | AAAAAA== |
| IPM.Appointment: TEST 6 |
| SOFT DELETE RESTORE |
| CreatedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2KwAA | AAAAAA== |
| IPM.SchedulePlus.FreeBusy.BinaryData: |
| MovedEvent | [MovedCopiedEventType]: | GRlvYJ3GL/RAArjVW2LAAA | AAAAAA== |
| IPM.Appointment: TEST 6 |
| DeletedEvent | [BaseObjectChangedEventType] | GRlvYJ3GL/RAArjVW2KwAA | AAAAAA== |
| No Messages Matched: ErrorItemNotFound |
| === OUTLOOK === |
| CREATE |
| CreatedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgECQAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| EXPANDED / CONTRACT / MOVE WITHIN CALENDAR |
| ModifiedEvent | [ModifiedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgECQAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| MOVED FOLDER / SOFT DELETE / SOFT DELETE RESTORE |
| MovedEvent | [MovedCopiedEventType] | RAAQUK0ABgAA5jp9kS9UdUCKFiIaz2NQeAAriVgUBAAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| COPIED WITHIN CALENDAR |
| CreatedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgECgAA | DwAAAA== |
| IPM.Appointment: TEST 5 |
| HARD DELETE |
| DeletedEvent | [BaseObjectChangedEventType] | RAAQUKzDsAAA5jp9kS9UdUCKFiIaz2NQeAAriVgECgAA | DwAAAA== |
| No Messages Matched: ErrorItemNotFound |
It looks like OWA is still quite different from Outlook, but now at least the event types and event names go together much more sensibly.