none
EWS API- Differences in ICalUid returned when appointments are created by Office 365 account vs. Microsoft Outlook Mac Client

    Question

  • Hi, 

    Please help, this is very strange behavior I have come across:

    Following is the issue:

    1. I used Office365 cloud account to test this before. Whenever, scheduled appointments are retrieved from an account using EWS Api, it returns ICalUid of an appointment in the following

    format: 040000008200E00074C5B7101A82E0080000000074BADF021787CF01000000000000000010000000A5805E16A0F892419C4ABE270A4EEBC7

    2. Today, I used the same account through Microsoft Outlook Client on Mac, and created few appointments in a calendar. The same EWS Api call, gives Appointments back with different format of ICalUid:

    For example: 7D9B63D2-74BD-4317-A083-DFE6C2BFC1B4

    The reason, its bothers because of the following I am trying to achieve:

    - I have a service account whose calendar is queried for appointments created in particular time interval. For example- for 2 days.

    - The Query FindAppointments returns all events in the start and end time. Single appointments are returned once, where recurring events are returned as all separate instances of that recurring event.

                CalendarFolder calendar = CalendarFolder.Bind(_service, WellKnownFolderName.Calendar, new PropertySet(BasePropertySet.FirstClassProperties));
                CalendarView cv = new CalendarView(start, end);
                cv.MaxItemsReturned = 1000;

                var meetings = new List<Meeting>();

                FindItemsResults<Appointment> masterResults = calendar.FindAppointments(cv);

    - Now, in the items returned, "Resources" are returned as empty; if that user is not an organizer of that appointment.

    - to get Resources part for that appointment, I need to query organizer's calendar to find out that exact appointment.

    To do that, I found following method in online search (on most of the forums), which works fine for type 1. of ICalUid mentioned above; but does not work for type 2. ICalUid mentioned above.

    [References:

    http://social.msdn.microsoft.com/Forums/en-US/26c2f76d-93bb-4a70-80e8-cf6cc9c66254/search-appointment-by-ical-in-ews-managed?forum=exchangesvrdevelopment

    http://stackoverflow.com/questions/3829039/get-the-organizers-calendar-appointment-using-ews-for-exchange-2010

    http://www.infinitec.de/post/2009/04/13/Searching-a-meeting-with-a-specific-UID-using-Exchange-Web-Services-2007.aspx

    ]

    Here is my code:

            private string GetObjectIdStringFromUid(string id)
            {
                var buffer = new byte[id.Length / 2];
                for (int i = 0; i < id.Length / 2; i++)
                {
                    var hexValue = byte.Parse(id.Substring(i * 2, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
                    buffer[i] = hexValue;
                }
                return Convert.ToBase64String(buffer);
            }

    // apt passed to this function, is an appointment retrieved from a service account, who is not an organizer of this appointment.

            private Appointment GetAppointmentFromOrganizer(Appointment apt)
            {
                ExchangeService service1 = Impersonate(apt.Organizer.Address.ToLower());

                var filter = new SearchFilter.IsEqualTo
                {
                    PropertyDefinition = new ExtendedPropertyDefinition
                        (DefaultExtendedPropertySet.Meeting, 0x03, MapiPropertyType.Binary),
                    Value = GetObjectIdStringFromUid(apt.ICalUid) //Hex value converted to byte and base64 encoded
                };
                var view = new ItemView(1) { PropertySet = new PropertySet(BasePropertySet.FirstClassProperties) };

                Appointment item = service1.FindItems(WellKnownFolderName.Calendar, filter, view).Items[0] as Appointment;
                item.Load();
                return item;
            }

    - I have tried using Appointment.Id.UniqueId instead of ICalUid to retrieve an event form Organizer's calendar, but it returns empty result.

    What exactly is the right way (or filter parameter) to pull out particular appointment from organizer's calendar?

    Your help is appreciated.

    Friday, June 13, 2014 10:50 PM

Answers

  • The problem with your code is this line and the fact your relying on the ICalUid

                    PropertyDefinition = new ExtendedPropertyDefinition
                        (DefaultExtendedPropertySet.Meeting, 0x03, MapiPropertyType.Binary),
                    Value = GetObjectIdStringFromUid(apt.ICalUid)

    My suggestion is that your don't rely on this property its setup by the client so it format can vary. If you rely on the GlobalObjectId extended property (or better the CleanGlobalObjectId) which are properties who's format is defined and used by Exchange and Outlook to correlate Appointment your code will always works. All you need to change is to load that property from the source appointment and search the Organizer calendar based on that property. eg

          Appointment newAppointment = new Appointment(service);
            newAppointment.Subject = "Test Subject";        
            newAppointment.Start = new DateTime(2012, 03, 27, 17, 00, 0);
            newAppointment.StartTimeZone = TimeZoneInfo.Local;
            newAppointment.EndTimeZone = TimeZoneInfo.Local;
            newAppointment.End = newAppointment.Start.AddMinutes(30);
            newAppointment.Save();
            newAppointment.Body = new MessageBody(Microsoft.Exchange.WebServices.Data.BodyType.Text, "test");
            newAppointment.RequiredAttendees.Add("attendee@domain.com");
            newAppointment.Update(ConflictResolutionMode.AlwaysOverwrite ,SendInvitationsOrCancellationsMode.SendOnlyToAll);
            ExtendedPropertyDefinition CleanGlobalObjectId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Meeting, 0x23, MapiPropertyType.Binary);
            PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
            psPropSet.Add(CleanGlobalObjectId);
            newAppointment.Load(psPropSet);
            object CalIdVal = null;
            newAppointment.TryGetProperty(CleanGlobalObjectId, out CalIdVal);
            Folder AtndCalendar = Folder.Bind(service, new FolderId(WellKnownFolderName.Calendar,"attendee@domain.com"));
            SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(CleanGlobalObjectId, Convert.ToBase64String((Byte[])CalIdVal));
            ItemView ivItemView = new ItemView(1);
            FindItemsResults<Item> fiResults = AtndCalendar.FindItems(sfSearchFilter, ivItemView);
            if (fiResults.Items.Count > 0) {
                //do whatever
            }
    Cheers
    Glen

     

    • Marked as answer by sn_12 Tuesday, June 24, 2014 9:42 PM
    Monday, June 16, 2014 6:51 AM

All replies

  • The problem with your code is this line and the fact your relying on the ICalUid

                    PropertyDefinition = new ExtendedPropertyDefinition
                        (DefaultExtendedPropertySet.Meeting, 0x03, MapiPropertyType.Binary),
                    Value = GetObjectIdStringFromUid(apt.ICalUid)

    My suggestion is that your don't rely on this property its setup by the client so it format can vary. If you rely on the GlobalObjectId extended property (or better the CleanGlobalObjectId) which are properties who's format is defined and used by Exchange and Outlook to correlate Appointment your code will always works. All you need to change is to load that property from the source appointment and search the Organizer calendar based on that property. eg

          Appointment newAppointment = new Appointment(service);
            newAppointment.Subject = "Test Subject";        
            newAppointment.Start = new DateTime(2012, 03, 27, 17, 00, 0);
            newAppointment.StartTimeZone = TimeZoneInfo.Local;
            newAppointment.EndTimeZone = TimeZoneInfo.Local;
            newAppointment.End = newAppointment.Start.AddMinutes(30);
            newAppointment.Save();
            newAppointment.Body = new MessageBody(Microsoft.Exchange.WebServices.Data.BodyType.Text, "test");
            newAppointment.RequiredAttendees.Add("attendee@domain.com");
            newAppointment.Update(ConflictResolutionMode.AlwaysOverwrite ,SendInvitationsOrCancellationsMode.SendOnlyToAll);
            ExtendedPropertyDefinition CleanGlobalObjectId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Meeting, 0x23, MapiPropertyType.Binary);
            PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties);
            psPropSet.Add(CleanGlobalObjectId);
            newAppointment.Load(psPropSet);
            object CalIdVal = null;
            newAppointment.TryGetProperty(CleanGlobalObjectId, out CalIdVal);
            Folder AtndCalendar = Folder.Bind(service, new FolderId(WellKnownFolderName.Calendar,"attendee@domain.com"));
            SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(CleanGlobalObjectId, Convert.ToBase64String((Byte[])CalIdVal));
            ItemView ivItemView = new ItemView(1);
            FindItemsResults<Item> fiResults = AtndCalendar.FindItems(sfSearchFilter, ivItemView);
            if (fiResults.Items.Count > 0) {
                //do whatever
            }
    Cheers
    Glen

     

    • Marked as answer by sn_12 Tuesday, June 24, 2014 9:42 PM
    Monday, June 16, 2014 6:51 AM
  • Thanks Glen.

    It worked exactly how I wanted.

    Tuesday, June 24, 2014 9:42 PM
  • Glen,

    It worked fine for me too, thanks, but this way it allways retrieve the recurring master event, in some cases I want to retrieve the related ocurrence.

    Do you understand what I mean? Is it Possible?


    Wednesday, June 6, 2018 1:25 PM
  • If you want to expand the recurrence you will need to use a Calendarview with Start and EndTime, you can still use the same property to make sure that your referencing the same appointment but you can't use a filter and CalendarView at the same time so just filter out the appointments you don't want after you expand for the time period that the occurrence is in.

    Cheers
    Glen

    Wednesday, June 6, 2018 11:46 PM