Enhancing Support For Custom Item Classes

The following proposal is a change that we’re considering for future Microsoft Exchange Server 2007 service packs and future releases of Exchange Server. Based on the feedback we’ve received, we have identified support for item classes, for which EWS doesn’t have a corresponding type, as one area where we can improve your experience with EWS. This proposed modification will change some of the default behavior, and before we make our final decision, we’d like to get your feedback. If you are aware of any potential problems or existing coding patterns that would break as a result of this design change, please leave your comments below.

BACKGROUND:
When EWS returns an item that has an ItemClass that doesn’t map to a strong type, it returns that item as an ItemType. For example, a developer could choose to store an item with a custom item class (i.e. “Item.Custom”) in Exchange. Because EWS doesn’t have a strong type for “Item.Custom”, the item would be returned as an ItemType. These items create problems for EWS developers because ItemType objects cannot be sent by using the SendItem method. These items cannot be sent because they lack a number of key properties – i.e. ToRecipients, CcRecipients, Sender, and so on. Another issue developers have when working with these items is that there is no way to mark them as Read/Unread. The potential solution we’ve come up with is to have EWS return these items as messages.

The MessageType derives from ItemType, so developers would gain new methods and functionality and there would be no loss of existing functionality with this solution. Exposing these additional properties would enable developers to Send, Reply, ReplyAll, and Forward these items as well as mark them as Read/Unread.

Existing code that creates an ItemType will continue to work by using the proxy objects or XML, but those same items would be returned (via FindItem or GetItem) as MessageType objects. For these MessageType objects, you would need to look at the associated ResponseObjects property to see if Reply or ReplyAll is allowed. For example, with this change, we would return a non-delivery report (NDR) as a MessageType. You would be allowed to forward it, but it doesn’t make sense to Reply or ReplyAll to an NDR.

SAMPLE CODE USING PROXY OBJECTS:
If you are using the auto-generated proxy objects, you shouldn’t notice any changes. One exception to this would be if your code is explicitly checking the item type that is returned. Because MessageType derives from ItemType, you would still be able to treat the returned item as an ItemType even though it is a MessageType.

GetItemType getRequest = new GetItemType();
getRequest.ItemIds = new BaseItemIdType[] { createResponseMessage.Items.Items[0].ItemId };
getRequest.ItemShape = new ItemResponseShapeType();
getRequest.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties;

GetItemResponseType getItemRespone = esb.GetItem(getRequest);
ItemInfoResponseMessageType getItemResponeMessage = getItemRespone.ResponseMessages.Items[0] as ItemInfoResponseMessageType;

// If your existing application has this line of code, it will keep working regardless of whether the item coming back is an item or a message.
ItemType returnedItem = getItemResponeMessage.Items.Items[0];

// If you wanted to take advantage of the enhanced behavior, you would now be able to cast these items (for which we don’t have a strong type) as message.
MessageType returnedItem = (MessageType)getItemResponeMessage.Items.Items[0];

SAMPLE CODE USING XML: The biggest change would be for developers who are sending/receiving raw XML and parsing specific nodes. The following code will not work after this change.

XmlNamespaceManager namespaceManager = new XmlNamespaceManager(new NameTable());
namespaceManager.AddNamespace("t", @"https://schemas.microsoft.com/exchange/services/2006/types");
namespaceManager.AddNamespace("m", @"https://schemas.microsoft.com/exchange/services/2006/messages");
namespaceManager.AddNamespace("soap", @"https://schemas.xmlsoap.org/soap/envelope/");

XmlDocument response = new XmlDocument();
int xmlStartIndex = responseText.IndexOf("<?xml");
response.LoadXml(responseText.Substring(xmlStartIndex));
string xPath = string.Format(@"//t:Items/t:Item/t:Subject[text()='{0}']", "MySubject");
XmlNodeList nodeList = response.SelectNodes(xPath, namespaceManager);

After the proposed change, response.SelectNodes would not find a children of “Items” called “Item” and therefore nodeList.Count will be 0. The XPath query would need to be updated to:
string xPath = string.Format(@"//t:Items/t:Message/t:Subject[text()='{0}']", "MySubject");

SERVER VERSIONS:
This proposed change will only affect requests that set the Version attribute of the RequestServerVersion SOAP header to Exchange2007_SP1. Requests made with the Version attribute set to Exchange2007, or requests where no RequestServerVersion SOAP header was specified, will continue to return these items as ItemType objects.

EXISTING BEHAVIOR:
  <m:GetItemResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:GetItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Items>
           <t:Item>
<t:ItemId Id="..." ChangeKey=".."/>
<t:ParentFolderId Id="..." ChangeKey="..."/>
<t:ItemClass>ABC.DEF</t:ItemClass>
<t:Subject>This is an ItemClass which EWS doesn’t have a strong type</t:Subject>

     ...
          </t:Item>
</m:Items>
</m:GetItemResponseMessage>
</m:ResponseMessages>
</m:GetItemResponse>

PROPOSED BEHAVIOR:
  <m:GetItemResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:GetItemResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Items>
           <t:Message>
<t:ItemId Id="..." ChangeKey=".."/>
<t:ParentFolderId Id="..." ChangeKey="..."/>
<t:ItemClass>ABC.DEF</t:ItemClass>
<t:Subject>This is an ItemClass which EWS doesn’t have a strong type</t:Subject>
...
<t:ConversationIndex>AQHIueIXa5lWW0xw20qwVRcT611b/Q==</t:ConversationIndex>
<t:ConversationTopic>ABC.DEF</t:ConversationTopic>
<t:InternetMessageId>&lt;<E4D3FFFB356BA34FAD06F517E1AECCE711C41DB278@Server.company.com&gt>;</t:InternetMessageId>
<t:IsRead>true</t:IsRead>
           </t:Message>
</m:Items>
</m:GetItemResponseMessage>
</m:ResponseMessages>
</m:GetItemResponse>

We think we’ve thought through most of the common scenarios for how people are using EWS, but this community is a rich source of customer experiences. If you are aware of any cases where this design change would cause problems, we want to know about it. Please leave your questions or comments below.

Comments

  • Anonymous
    June 19, 2008
    Actually, you can set an ItemType instance as read/unread, etc. You just have to set the PR_MESSAGE_FLAGS (0x0E07 tag, with a property type of MapiPropertyTypeType.Integer) ExtendedPropertyType to 0x0 for unread or 0x1 for read. I haven't checked, but I'd wager that you can set those other properties as well, you just have to know the property tag for the ExtendedFiedlURI.

  • Anonymous
    June 20, 2008
    What if the custom class is better mapped to a Contact or Appointment item? Perhaps you could allow the developer to specify the "base" type to attempt to return.

  • Anonymous
    October 07, 2008
    We have just released update rollup 4 (RU4) for Exchange 2007 SP1 . This rollup fixes some bugs in Exchange

  • Anonymous
    April 16, 2009
    The comment has been removed

  • Anonymous
    April 17, 2009
    ConversationIndex and ConversationTopic are both read-only properties.

  • Anonymous
    January 20, 2010
    The comment has been removed