Creating extended property using EWS and access it

2019-07-04 12:04发布

问题:

I am currently working on EWS to have some integration of our company application with Exchange 2010. I am using EWS to create appoinment to Exchange 2010 and it works fine; but recently I tried to add some custom/extended property when creating the appointment, below is my code to add the extended property.

Dim customField As New ExtendedPropertyDefinition(DefaultExtendedPropertySet.PublicStrings, "MyCustomField", MapiPropertyType.String)

appointment.SetExtendedProperty(customField, "CustomFieldValue")

The above codes able to create the custom field to the appointment.

Now here is my problem. When I open up the appointment in Outlook that I created and go to "Developer > Design This Form", then "All Fields" tab, I only see the custom field I created in the "User-defined field in folder" but not in "User-defined field in this item".

I also making an Outlook Add-in to react to the custom field that I created using the EWS when user opens up the appointment in Outlook, when I tried to look for the custom field, couldn't find the custom field, because the custom field is created in "User-defined field in folder" but not in "User-defined field in this item".

This is the codes in the Outlook Add-in and will execute when user opens an apointment in Outlook. But because the custom field is not in "in this item", the .Find() returns Nothing.

Dim appt As Outlook.AppointmentItem
appt = TryCast(inspector.CurrentItem, Outlook.AppointmentItem)
If appt.UserProperties.Find("MyCustomField") Is Nothing Then
    'Some action
Else
    'Some action
End If

What I want to achieve is to create an appointment with the custom field (extended property) using EWS, and then read the custom field (extended property) in Outlook Add-in when user open the appointment in Outlook.

EDIT:

The value that I assigned to the custom field using EWS is shown in the "User-defined field in folder". How do I retrieve the value from my Outlook Add-in? Maybe I can retrieve the value and add the custom field to the item and with the value?

Thanks.

回答1:

The answer is here: http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/2a98b4ab-0fbc-4863-8303-48711a18a050

Can't access the extended property created by EWS using UserProperties. But can access using PropertyAccessor.

outlookItem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/yourProp")


回答2:

I'm posting this as another answer showing some actual (Delphi) code, because that was missing from the first answer.
AAppointmentItem is an OLEVariant

const
   GUID_PS_PUBLIC_STRINGS = '{00020329-0000-0000-C000-000000000046}';
   cPublicStringNameSpace = 'http://schemas.microsoft.com/mapi/string/' + GUID_PS_PUBLIC_STRINGS + '/';

var
   lPropertyAccessor: OleVariant;
   lSchemaName, lValue: String;

begin   
   // Use the PropertyAccessor because Outlook UserProperties() can't access the extended properties created by EWS 
   // Use the 'string subnamespace of the MAPI namespace' (http://msdn.microsoft.com/en-us/library/office/ff868915.aspx)
   // with the PS_PUBLIC_STRINGS GUID from http://msdn.microsoft.com/en-us/library/bb905283%28v=office.12%29.aspx
   lPropertyAccessor := AAppointmentItem.PropertyAccessor;
   lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLID;  // Name constants defined elsewhere
   try
      lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLID;
      lValue := lPropertyAccessor.GetProperty(lSchemaName);
      lEvent.CustSyncTTID := StrToInt(lValue);
   except
   end;
   try
      lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLSYNCTIME;
      lValue := lPropertyAccessor.GetProperty(lSchemaName);
      lEvent.CustSyncDate := UTCString2LocalDateTime(lValue);
   except
   end;
   try
      lSchemaName := cPublicStringNameSpace + PROPERTY_TIMETELLSYNCID;
      lValue := lPropertyAccessor.GetProperty(lSchemaName);
      lEvent.CustSyncEntryID := lValue;
   except
   end;

Note the many try excepts because we are doing late binding; 'early' would've been better (http://blog.depauptits.nl/2012/04/safely-accessing-named-properties-in.html)

Also, We are retrieving multiple user properties, so GetProperties() is actually better.

FWIW, this was the old code using UserProperties (lProperty is OLEVariant)

lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLID);
if IDispatch(lProperty) <> nil then
  lEvent.CustSyncTTID :=  lProperty.Value;
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLSYNCTIME);
if IDispatch(lProperty) <> nil then
  lEvent.CustSyncDate :=  lProperty.Value;
lProperty := AAppointmentItem.UserProperties.Find(PROPERTY_TIMETELLSYNCID);
if IDispatch(lProperty) <> nil then
  lEvent.CustSyncEntryID := lProperty.Value;            

[Edited to add 2013-6-10]

And here is the code modified to handle all three properties at once using GetProperties (as MS recommends):

lPropertyAccessor := AAppointmentItem.PropertyAccessor;
lSchemas := VarArrayOf([cPublicStringNameSpace + PROPERTY_TIMETELLID,
                        cPublicStringNameSpace + PROPERTY_TIMETELLSYNCTIME,
                        cPublicStringNameSpace + PROPERTY_TIMETELLSYNCID]);
try
  lValues := lPropertyAccessor.GetProperties(lSchemas);
  if VarType(lValues[0]) <> varError then
     lEvent.CustSyncTTID := lValues[0];
  if VarType(lValues[1]) <> varError then
  begin
     lDT := lValues[1];
     lDT := TTimeZone.Local.ToLocalTime(lDT);
     lEvent.CustSyncDate := lDT;
  end;
  if VarType(lValues[2]) <> varError then
    lEvent.CustSyncEntryID := lValues[2];
except
end;