1
votes

I've got a windows service to read calendar items from Exchange and store them in my application's DB against each user. Now I wonder what is the best way to mark an item on Exchange to not be retrieved in the next service run after storing it?

I tried to add an extended property to the calendar item and set it's value and then search based on it's value each time:

DateTime startDate = DateTime.Now;
DateTime endDate = startDate.AddDays(60);
const int NUM_APPTS = 60;    
// Set the start and end time and number of appointments to retrieve.
CalendarView cView = new CalendarView(startDate, endDate, NUM_APPTS);

Guid myPropertyId = new Guid("{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}");
ExtendedPropertyDefinition myExtendedProperty = new ExtendedPropertyDefinition(myPropertyId, "SyncFlag", MapiPropertyType.Boolean);

// Limit the properties returned to the appointment's subject, start time, end time and the extended property.
 cView.PropertySet = new PropertySet(AppointmentSchema.Subject, AppointmentSchema.Start, AppointmentSchema.End, AppointmentSchema.Location, myExtendedProperty);

// Retrieve a collection of appointments by using the calendar view.
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
searchFilterCollection.Add(new SearchFilter.IsEqualTo(AppointmentSchema.Start, DateTime.Now));
searchFilterCollection.Add(new SearchFilter.IsEqualTo(AppointmentSchema.End, DateTime.Now.AddDays(60)));

searchFilterCollection.Add(new SearchFilter.IsNotEqualTo(myExtendedProperty, true)); //Do not fetch already marked calendar items

SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection);

FindItemsResults<Item> appointments = service.FindItems(WellKnownFolderName.Calendar, searchFilter, cView);

Searching calendar items using this code throws this exception:

Restrictions and sort order may not be specified for a CalendarView.

And I'm not sure if it's the best way to do it either. Any idea?

Thanks

1

1 Answers

2
votes

One way to this is to use the SyncFolderItems method. It will return the items that were changed since the last call. All you have to do is save a synchronization "cookie" between each call.

You should also filter out the appointment items that were created since your last call.

This below code snippet should do the trick.

static private void GetChangedItems()
{
    // Path to cookie
    string syncStateFileName = @"c:\temp\ewssyncstate.txt";

    try
    {
        var service = GetServiceAP();
        bool moreChangesAvailable = false;

        do
        {
            string syncState = null;


            if (File.Exists(syncStateFileName))
            {
                // Read cookie
                syncState = File.ReadAllText(syncStateFileName);
            }

            ChangeCollection<ItemChange> icc = service.SyncFolderItems(new FolderId(WellKnownFolderName.Calendar), PropertySet.FirstClassProperties, null, 10, SyncFolderItemsScope.NormalItems, syncState);

            if (icc.Count == 0)
            {
                Console.WriteLine("There are no item changes to synchronize.");
            }
            else
            {
                syncState = icc.SyncState;

                // Save cookie
                File.WriteAllText(syncStateFileName, syncState);

                moreChangesAvailable = icc.MoreChangesAvailable;

                // Only get appointments that were created since last call
                var createdItems = icc
                    .Where(i => i.ChangeType == ChangeType.Create)
                    .Select(i => i.Item as Appointment)
                    ;

                if (createdItems.Any())
                {
                    service.LoadPropertiesForItems(createdItems, PropertySet.FirstClassProperties);

                    foreach (Appointment appointment in createdItems)
                    {
                        Console.WriteLine(appointment.Subject);
                    }
                }
            }
        }
        while (moreChangesAvailable);

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
}