InfiniTec - Henning Krauses Blog

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

Manipulation of extended properties with Exchange 2007 using the ExtendedPropertyType type

To access MAPI properties or custom Outlook properties using the Exchange 2007 Web Services, the ExtendedPropertyType type is used.

Here is a class diagram of the ExtendedPropertyType and its associated properties:


Class diagram of the ExtendedPropertyType type and its associated properties (click to enlarge)

The ExtendedPropertyType has two properties which need to be filled: Item and ExtendedFieldUri. The latter one identfifies the property while the first one contains the value of the property. The Item property is of type object which suggests that it contains the property value in its native representation (e.g. a date stored as System.DateTime, a boolean value as type System.Boolean and so on). Unfortunately, this is not the case. If the property is multi-valued, the Item property contains a array of strings. Otherwise, it contains only one string. To actually do something with the value, it needs to be converted to it's corresponding type.

Here is an example request which performs a FindItem operation on the calendar of a mailbox, requesting the end date of the appointments using an extended property:

    1 privatestatic T[] DeserializeValues<T>(object[] items)

    2 {

    3     if (items == null) returnnew T[0];

    4 

    5     returnArray.ConvertAll<object, T>(items, delegate(object input) { return DeserializeValue<T>((string) input); });

    6 }

    7 

    8 privatestatic T DeserializeValue<T>(string item)

    9 {

   10     TypeConverter converter;

   11     Type type;

   12 

   13     if (string.IsNullOrEmpty(item)) returndefault(T);

   14 

   15     type = Nullable.GetUnderlyingType(typeof (T)) ?? typeof (T);

   16 

   17     if (type == typeof(byte[])) return (T)​(object)Convert.FromBase64String(item);

   18     elseif (type == typeof(DateTime)) return (T) (object) XmlConvert.ToDateTime(item, XmlDateTimeSerializationMode.Utc).ToLocalTime();

   19     elseif (type.IsEnum) return (T)Enum.Parse(type, item);

   20     else

   21     {

   22         converter = TypeDescriptor.GetConverter(type);

   23         return (T)converter.ConvertFromString(item);

   24     }

   25 }

   26 

   27 publicstaticvoid Main(string[] args)

   28 {

   29     ExchangeServiceBinding client = newExchangeServiceBinding();

   30 

   31     client.Url = "https://w2k3x64.contoso.local/ews/exchange.asmx";

   32     client.Credentials = newNetworkCredential("administrator", "password", "contoso");

   33 

   34     DistinguishedFolderIdType folderId = newDistinguishedFolderIdType();

   35     folderId.Id = DistinguishedFolderIdNameType.calendar;

   36 

   37     FindItemType request = newFindItemType();

   38 

   39     PathToExtendedFieldType propertyId = newPathToExtendedFieldType();

   40     propertyId.DistinguishedPropertySetId = DistinguishedPropertySetType.Appointment;

   41     propertyId.PropertyId = 0x820e;

   42     propertyId.PropertyType = MapiPropertyTypeType.SystemTime;

   43     propertyId.PropertyIdSpecified = true;

   44     propertyId.DistinguishedPropertySetIdSpecified = true;

   45 

   46     request.ParentFolderIds = newBaseFolderIdType[] {folderId};

   47     request.ItemShape = newItemResponseShapeType();

   48     request.Traversal = ItemQueryTraversalType.Shallow;

   49     request.ItemShape.BaseShape = DefaultShapeNamesType.Default;

   50     request.ItemShape.AdditionalProperties = newBasePathToElementType[] { propertyId };

   51 

   52     FindItemResponseType result = client.FindItem(request);

   53 

   54     if (result.ResponseMessages.Items[0].ResponseCode != ResponseCodeType.NoError)

   55     {

   56         Console.Out.WriteLine("Error = {0}", result.ResponseMessages.Items[0].ResponseCode);

   57         return;

   58     }

   59 

   60     FindItemResponseMessageType findItemResponse = (FindItemResponseMessageType)result.ResponseMessages.Items[0];

   61     ItemType[] items = ((ArrayOfRealItemsType)findItemResponse.RootFolder.Item).Items;

   62     if (items != null)

   63     {

   64         foreach (ItemType childItem in items)

   65         {

   66             Console.Out.WriteLine("item.Subject = {0}", childItem.Subject);

   67             Console.Out.WriteLine("ParseValue<DateTime?>(childItem.ExtendedProperty[0].Item) = {0}", DeserializeValue<DateTime?>((string)childItem.ExtendedProperty[0].Item));

   68         }

   69     }

   70 

   71     Console.WriteLine("Finished.");

   72     Console.ReadLine();

   73 }

The content of the main function is actually the boring part. More interesting is the DeserializeValue<T> method which takes a string and converts it to the specified value T. In this example, the value is converted to a nullable DateTime. This method in called in line 67.

To update the property, these methods can be used to serialize a typed value to a string:

    1 privatestaticExtendedPropertyType CreateExtendedProperty<T>(PathToExtendedFieldType id, IEnumerable<T> values)

    2 {

    3     ExtendedPropertyType result = newExtendedPropertyType();

    4 

    5     result.ExtendedFieldURI = id;

    6     result.Item = (values != null) ? newList<T>(values).ConvertAll<string>(delegate(T input) { return SerializeValue(input); }).ToArray() : null;

    7 

    8     return result;

    9 }

   10 

   11 privateExtendedPropertyType CreateExtendedProperty<T>(PathToExtendedFieldType id, T value)

   12 {

   13     ExtendedPropertyType result = newExtendedPropertyType();

   14     result.ExtendedFieldURI = id;

   15     result.Item = SerializeValue(value);

   16 

   17     return result;

   18 }

   19 

   20 privatestaticstring SerializeValue<T>(T value)

   21 {

   22     Type type;

   23     TypeConverter converter;

   24     object result;

   25 

   26     result = value;

   27 

   28     if (result == null) returnnull;

   29 

   30     //Unbox nullable types

   31     type = Nullable.GetUnderlyingType(typeof(T));

   32     if (type != null)

   33     {

   34         converter = newNullableConverter(typeof(T));

   35         result = converter.ConvertTo(value, type);

   36     }

   37     else type = typeof(T);

   38 

   39     if (type.IsEnum)

   40     {

   41         result = Convert.ChangeType(result, Enum.GetUnderlyingType(type));

   42         return result.ToString();

   43     }

   44     elseif (type == typeof(DateTime))

   45     {

   46         returnXmlConvert.ToString(((DateTime)result).ToUniversalTime(), XmlDateTimeSerializationMode.Utc);

   47     }

   48     elseif (type == typeof(bool))

   49     {

   50         return ((bool)result) ? "1" : "0";

   51     }

   52     elseif (type == typeof(byte[]))

   53     {

   54         returnConvert.ToBase64String((byte[])result);

   55     }

   56     else

   57     {

   58         returnstring.Format(CultureInfo.InvariantCulture, "{0}", result);

   59     }

   60 }

The SerializeValue<T> method can handle all formats used by the Exchange Web Services and copes with nullable types also.


Technorati:

Posted by Henning Krause on Sunday, October 21, 2007 12:00 AM, last modified on Thursday, November 25, 2010 4:25 AM
Permalink | Post RSSRSS comment feed