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.