[Exchange] Exchange의 EWS에서 일정관련 연계 작업시 GlobalObjectId를 이용해 일정 찾기
일정을 사용자가 작성하면 ItemId와 GlobalObjectId가 생성이 된다.
ItemId는 Exchange에서 Item을 인식하는 Unique 값으로 유일한 값을 나타낸다. 그리고 다른 사용자와의 일정에서 공통적인 값을 GlobalObjectId를 사용하여 같은 일정인지를 알아 낼 수 있다.
사용자A가 일정을 만들 때 사용자B를 참조인으로 입력 후 생성하면
사용자A : ItemId : aa1, GlobalObjectId : abcdef
사용자B : ItemId : bb1, GlobalObjectId : abcdef
와 같이 생성이 되게 된다.
그러면 타 시스템에서 EWS를 사용하여 정보를 알아 내기 위해서 아래와 같은 코드로 GlobalObjectId를 가져올 수 있다.
Appointment exItem = null; // GlobalObjectId ExtendedPropertyDefinition globalObjectId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Meeting, 0x03, MapiPropertyType.Binary); //하나의 객체에 대해서만 바인딩 exItem = Item.Bind(service.Service, notification.ItemId, new PropertySet( ItemSchema.Id, ItemSchema.Subject, AppointmentSchema.ICalUid, globalObjectId)) as Appointment;
[코드1] GlobalObjectId의 값을 가져오는 코드
위 코드에서 ExtendedPropertyDefinition으로 확장 프로퍼티를 사용해서 가져와야 하며 선언 시 '0x03'을 입력하고 Binary를 선택해야 한다. 이제 넘겨진 값을 '코드2'에서와 같이 스트링으로 변환해서 사용 할 수 있다.
Convert.ToBase64String((byte[])exItem.ExtendedProperties[0].Value);
[코드2] Binary 형식을 스트링으로 변환하는 코드
이와 같은 코드로 다른 시스템과 연계하여 여러사람에 관계된 같은 일정을 찾아서 변경 해 줄 수 있을 것이다. 그렇지만 예외 케이스가 있다. 반복 일정에서 특정 항목만 편집하여 참조인을 추가 하는 케이스에서는 GlobalObjectId가 변경이 일어 나게 된다. 아래 글에서 설명이 나와 있다.
Using GlobalObjectId poses a problem however…If you were to create a recurring appointment and invite one attendee for only one instance of that recurring appointment that attendee ends up with only the one exception instance of the parent recurring appointment in their calendar. This is called an “orphaned” appointment. This type of appointment’s GlobalObjectId has additional information in it related to the exception date (for more information look at PidLidGlobalObjectId in MS-OXOCAL). The bottom line here is that this orphaned instance in this one attendee’s calendar will have a GlobalObjectId, and therefore UID, which doesn’t match the related appointments in the other attendee’s and organizer’s calendar. Henning’s code won’t work in this specific scenario…
참조 URL : http://blogs.msdn.com/b/mstehle/archive/2009/09/02/ews-uid-not-always-the-same-for-orphaned-instances-of-the-same-meeting.aspx
그래서 위의 문제점과 관련하여 CleanGlobalObjectId 라는 것이 존재하고 이는 위의 같은 CASE일때도 Id가 달라 지지 않는 프로퍼티를 사용해야 할 것이다.
The format of this property is the same as that of LID_GLOBAL_OBJID (PidLidGlobalObjectId). The value of this property must be equal to the value of LID_GLOBAL_OBJID, except the YH, YL, M, and D fields must be zero. All objects that refer to an Instance of a recurring series (including an orphan instance), as well as the recurring series itself, will have the same value for this property.
참고 URL : http://msdn.microsoft.com/en-us/library/cc839502.aspx
그래서 결론 적으로 아래 코드처럼 ClearnGlobalObjectId를 사용해서 값을 가져와서 연계 하면 변하지 않는 값으로 외부 시스템과 연동할 수 있을 것이다.
// GlobalObjectId // ExtendedPropertyDefinition globalObjectId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Meeting, 0x03, MapiPropertyType.Binary); // LID_GLOBAL_OBJID ExtendedPropertyDefinition globalObjectId = new ExtendedPropertyDefinition(DefaultExtendedPropertySet.Meeting, 0x23, MapiPropertyType.Binary);
[코드3] ClearnGlobalObjectId로 변경한 코드