InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Saving custom data on Exchange elements with The Exchange WebServices

The database used by Exchange is quite a versatile one. A developer can save custom data on each item by creating additional properties.

Generally, there are two types of identification for a property: Either, a property id used (for example PR_ENTRYID which has an id of 0x0fff) or a name. Additionally, some properties live in so called property sets, like most of the task fields. There are some predefined property sets, but a developer can choose to create his own. Since property sets are identified by a GUID, it is rather unlikely that two developers select a property set which collide with each other. In addition to the property name, a property also has a data type. The valid types are defined in the MapiPropertyTypeType enumeration.

One property set is of particular interest, namely the one called PublicStrings. All custom properties created with Outlook are stored in this set. If a custom property is designed to be used by custom Outlook formulas, the developer must choose this property set. In any other case, it is better to create a random GUID and use that property set to prevent collisions with other applications.

So, how are these properties accessed? The answer can be found in the PathToExtendedFieldType. The following code reads the custom Outlook property “CustomOutlookProperty”, which has a data type of string from a given item:

   1: public void GetRequest(ItemIdType itemId)
   2: {
   3:     using (var binding = CreateEwsBinding())
   4:     {
   5:         var customOutlookPropertyPath = new PathToExtendedFieldType
   6:             {
   7:                 DistinguishedPropertySetId = DistinguishedPropertySetType.PublicStrings,
   8:                 DistinguishedPropertySetIdSpecified = true,
   9:                 PropertyName = "CustomOutlookProperty",
  10:                 PropertyType = MapiPropertyTypeType.String
  11:             };
  12:         var request = new GetItemType
  13:               {
  14:                   ItemIds = new[] {itemId},
  15:                   ItemShape = new ItemResponseShapeType
  16:                     {
  17:                         AdditionalProperties = new[]
  18:                                {
  19:                                    customOutlookPropertyPath
  20:                                }
  21:                     }
  22:               };
  23:  
  24:         var response = binding.GetItem(request);
  25:  
  26:         // Need to check response for errors. Ommited for clarity
  27:  
  28:         var item = ((ItemInfoResponseMessageType) response.ResponseMessages.Items[0]).Items.Items[0];
  29:         var customOutlookPropertyValue =
  30:             (from extendedProperty in item.ExtendedProperty
  31:              where
  32:                  extendedProperty.ExtendedFieldURI.DistinguishedPropertySetId == DistinguishedPropertySetType.PublicStrings &&
  33:                  extendedProperty.ExtendedFieldURI.PropertyName == "CustomOutlookProperty"
  34:              select (string) extendedProperty.Item).FirstOrDefault();
  35:     }
  36: }

The important thing happens in lines 5 through 11. Theses lines define the path to the custom outlook property.

If you want to access a custom property that should not be directly available via Outlook, create a custom GUID for your application. For this example, I use this code:

   1: private static readonly Guid PrivatePropertySetId = new Guid("9C24B417-DDC1-4F5F-974D-E35FCF6E9FE2");

Then, replace the lines 5 through 11 with this code:

   1: var customOutlookPropertyPath = new PathToExtendedFieldType
   2:     {
   3:         PropertySetId = PrivatePropertySetId.ToString(),
   4:         PropertyName = "CustomProperty",
   5:         PropertyType = MapiPropertyTypeType.String
   6:     };

To extract the property from the response, use this snippet:

   1: var item = ((ItemInfoResponseMessageType) response.ResponseMessages.Items[0]).Items.Items[0];
   2: var customPropertyValue =
   3:     (from extendedProperty in item.ExtendedProperty
   4:      where
   5:         PrivatePropertySetId.ToString().Equals(extendedProperty.ExtendedFieldURI.PropertySetId, StringComparison.OrdinalIgnoreCase) &&
   6:          extendedProperty.ExtendedFieldURI.PropertyName == "CustomProperty"))
   7:      select (string) extendedProperty.Item).FirstOrDefault();

Note, that I used the the Equals method along with the comparison mode OrdinalIgnoreCase to compare the two property set ids.


Posted by Henning Krause on Friday, March 27, 2009 6:12 PM, last modified on Monday, November 29, 2010 8:30 PM
Permalink | Post RSSRSS comment feed