Answered by:
Edit Master Category List in Exchange 2010 via EWS?

Question
-
Hello,
We developed an application that includes editing the master category list using WebDAV (for use with Exchange 2007 and Outlook 2007).
I've read that Exchange Web Services does not allow you to access hidden messages, and thus cannot access the hidden message that contains the master category list (that hasmessage class IPM.Configuration.CategoryList). I've learned that WebDAV is no longer available in Exchange 2010.
Does anyone know, will Exchange Web Services in Exchange 2010 add support to access hidden messages and/or support editing the master category list?
Thanks,
Greg
See also: http://www.infinitec.de/post/2008/05/Working-with-the-MasterCategoryList-Via-WebDAV.aspx
http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/9177b31f-c6d3-4278-845a-008292fdf586/Monday, August 24, 2009 8:43 PM
Answers
-
Greg,
Exchange 2010 EWS does support Folder Associated Items (FAIs, or hidden messages). You can create them by using the IsAssociated property of messages, and you can query them with FindItem by using the new Associated value of the ItemTraversal enumeration.
EWS in Exchange 2010 also exposes the new UserConfiguration APIs. With these APIs, you can access FAIs in a more robust and strongly-typed way. Among other things, you can read and update the Master Category List via the UserConfiguration APIs. Note however that this will give you "raw" access to the MCL, which is stored as an XML document. To manipulate the list, you will have to parse and/or update that XML manually.
The below code implements a class that reads the Master Category List using the UserConfiguration class of the EWS Managed API RC:
public sealed class Category { private string name; private Color color; internal Category(string name, Color color) { this.name = name; this.color = color; } public string Name { get { return this.name; } } public Color Color { get { return this.color; } } } public sealed class MasterCategoryList : IEnumerable<Category> { private static Color[] CategoryColors = new Color[] { Color.FromRgb(0xFF, 0xFF, 0xFF), Color.FromRgb(0xE4, 0x63, 0x6A), Color.FromRgb(0xF4, 0x94, 0x54), Color.FromRgb(0xFF, 0xCA, 0x4C), Color.FromRgb(0xFF, 0xFE, 0x3D), Color.FromRgb(0x83, 0xD1, 0x7A), Color.FromRgb(0x7B, 0xD2, 0xB5), Color.FromRgb(0xB0, 0xC1, 0x8A), Color.FromRgb(0x72, 0x9B, 0xD9), Color.FromRgb(0x92, 0x78, 0xD1), Color.FromRgb(0xC3, 0x82, 0xA2), Color.FromRgb(0xC4, 0xCC, 0xDD), Color.FromRgb(0x4B, 0x59, 0x78), Color.FromRgb(0xA8, 0xA8, 0xA8), Color.FromRgb(0x52, 0x52, 0x52), Color.FromRgb(0x00, 0x00, 0x00), Color.FromRgb(0xAB, 0x1D, 0x24), Color.FromRgb(0xB1, 0x4F, 0x0D), Color.FromRgb(0xAB, 0x7B, 0x05), Color.FromRgb(0x99, 0x94, 0x00), Color.FromRgb(0x35, 0x79, 0x2B), Color.FromRgb(0x2E, 0x7D, 0x64), Color.FromRgb(0x5F, 0x6C, 0x3A), Color.FromRgb(0x2A, 0x51, 0x91), Color.FromRgb(0x50, 0x32, 0x8F), Color.FromRgb(0x82, 0x37, 0x5F) }; private ExchangeService service; private Mailbox mailbox; private Dictionary<string, Category> categories = new Dictionary<string, Category>(); public MasterCategoryList(ExchangeService service, Mailbox mailbox) { if (service.RequestedServerVersion < ExchangeVersion.Exchange2010) { throw new NotSupportedException("The Master Category List can only be accessed on an Exchange 2010 server or later."); } this.service = service; this.mailbox = mailbox; } public MasterCategoryList(ExchangeService service) : this(service, null) { } public void Load() { // Read the Master Category List from the Calendar folder. The MCL is stored as XML // in a UserConfiguration item. Each Category is stored in an element and is defined // by a series of attributes like "name" and "color". FolderId parentFolderId; if (this.mailbox != null) { parentFolderId = new FolderId(WellKnownFolderName.Calendar, this.mailbox); } else { parentFolderId = WellKnownFolderName.Calendar; } UserConfiguration owaCategories = new UserConfiguration( this.service, "CategoryList", parentFolderId); owaCategories.Load(UserConfigurationProperties.XmlData); MemoryStream stream = new MemoryStream(owaCategories.XmlData); XmlTextReader xmlReader = new XmlTextReader(stream); // The Master Category List looks like this: // // <?xml version="1.0" encoding="utf-8" ?> // <categories default="" lastSavedTime="2008-05-16T05:08:09.004819Z" xmlns="CategoryList.xsd"> // <category name="Red" color="0" ... /> // </categories> // // There are actually 13 attributes on the category element. We only care about name and color. while (xmlReader.Read()) { if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "category") { if (xmlReader.HasAttributes) { int colorIndex; try { // Color 0 is the default, actual category colors start at index 1 colorIndex = Convert.ToInt32(xmlReader.GetAttribute("color")) + 1; if (colorIndex < 0 && colorIndex >= MasterCategoryList.CategoryColors.Length) { colorIndex = 0; } } catch { colorIndex = 0; } string categoryName = xmlReader.GetAttribute("name"); this.categories.Add( categoryName, new Category( categoryName, MasterCategoryList.CategoryColors[colorIndex])); } } } } public bool TryGetCategory(string categoryName, out Category category) { return this.categories.TryGetValue(categoryName, out category); } #region IEnumerable<Category> Members IEnumerator<Category> IEnumerable<Category>.GetEnumerator() { return this.categories.Values.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.categories.Values.GetEnumerator(); } #endregion }
David Claux | Program Manager - Exchange Web Services- Proposed as answer by David Claux - MSFT Monday, August 24, 2009 9:36 PM
- Marked as answer by gkriggs Monday, August 24, 2009 10:09 PM
Monday, August 24, 2009 9:35 PM
All replies
-
Greg,
Exchange 2010 EWS does support Folder Associated Items (FAIs, or hidden messages). You can create them by using the IsAssociated property of messages, and you can query them with FindItem by using the new Associated value of the ItemTraversal enumeration.
EWS in Exchange 2010 also exposes the new UserConfiguration APIs. With these APIs, you can access FAIs in a more robust and strongly-typed way. Among other things, you can read and update the Master Category List via the UserConfiguration APIs. Note however that this will give you "raw" access to the MCL, which is stored as an XML document. To manipulate the list, you will have to parse and/or update that XML manually.
The below code implements a class that reads the Master Category List using the UserConfiguration class of the EWS Managed API RC:
public sealed class Category { private string name; private Color color; internal Category(string name, Color color) { this.name = name; this.color = color; } public string Name { get { return this.name; } } public Color Color { get { return this.color; } } } public sealed class MasterCategoryList : IEnumerable<Category> { private static Color[] CategoryColors = new Color[] { Color.FromRgb(0xFF, 0xFF, 0xFF), Color.FromRgb(0xE4, 0x63, 0x6A), Color.FromRgb(0xF4, 0x94, 0x54), Color.FromRgb(0xFF, 0xCA, 0x4C), Color.FromRgb(0xFF, 0xFE, 0x3D), Color.FromRgb(0x83, 0xD1, 0x7A), Color.FromRgb(0x7B, 0xD2, 0xB5), Color.FromRgb(0xB0, 0xC1, 0x8A), Color.FromRgb(0x72, 0x9B, 0xD9), Color.FromRgb(0x92, 0x78, 0xD1), Color.FromRgb(0xC3, 0x82, 0xA2), Color.FromRgb(0xC4, 0xCC, 0xDD), Color.FromRgb(0x4B, 0x59, 0x78), Color.FromRgb(0xA8, 0xA8, 0xA8), Color.FromRgb(0x52, 0x52, 0x52), Color.FromRgb(0x00, 0x00, 0x00), Color.FromRgb(0xAB, 0x1D, 0x24), Color.FromRgb(0xB1, 0x4F, 0x0D), Color.FromRgb(0xAB, 0x7B, 0x05), Color.FromRgb(0x99, 0x94, 0x00), Color.FromRgb(0x35, 0x79, 0x2B), Color.FromRgb(0x2E, 0x7D, 0x64), Color.FromRgb(0x5F, 0x6C, 0x3A), Color.FromRgb(0x2A, 0x51, 0x91), Color.FromRgb(0x50, 0x32, 0x8F), Color.FromRgb(0x82, 0x37, 0x5F) }; private ExchangeService service; private Mailbox mailbox; private Dictionary<string, Category> categories = new Dictionary<string, Category>(); public MasterCategoryList(ExchangeService service, Mailbox mailbox) { if (service.RequestedServerVersion < ExchangeVersion.Exchange2010) { throw new NotSupportedException("The Master Category List can only be accessed on an Exchange 2010 server or later."); } this.service = service; this.mailbox = mailbox; } public MasterCategoryList(ExchangeService service) : this(service, null) { } public void Load() { // Read the Master Category List from the Calendar folder. The MCL is stored as XML // in a UserConfiguration item. Each Category is stored in an element and is defined // by a series of attributes like "name" and "color". FolderId parentFolderId; if (this.mailbox != null) { parentFolderId = new FolderId(WellKnownFolderName.Calendar, this.mailbox); } else { parentFolderId = WellKnownFolderName.Calendar; } UserConfiguration owaCategories = new UserConfiguration( this.service, "CategoryList", parentFolderId); owaCategories.Load(UserConfigurationProperties.XmlData); MemoryStream stream = new MemoryStream(owaCategories.XmlData); XmlTextReader xmlReader = new XmlTextReader(stream); // The Master Category List looks like this: // // <?xml version="1.0" encoding="utf-8" ?> // <categories default="" lastSavedTime="2008-05-16T05:08:09.004819Z" xmlns="CategoryList.xsd"> // <category name="Red" color="0" ... /> // </categories> // // There are actually 13 attributes on the category element. We only care about name and color. while (xmlReader.Read()) { if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.Name == "category") { if (xmlReader.HasAttributes) { int colorIndex; try { // Color 0 is the default, actual category colors start at index 1 colorIndex = Convert.ToInt32(xmlReader.GetAttribute("color")) + 1; if (colorIndex < 0 && colorIndex >= MasterCategoryList.CategoryColors.Length) { colorIndex = 0; } } catch { colorIndex = 0; } string categoryName = xmlReader.GetAttribute("name"); this.categories.Add( categoryName, new Category( categoryName, MasterCategoryList.CategoryColors[colorIndex])); } } } } public bool TryGetCategory(string categoryName, out Category category) { return this.categories.TryGetValue(categoryName, out category); } #region IEnumerable<Category> Members IEnumerator<Category> IEnumerable<Category>.GetEnumerator() { return this.categories.Values.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.categories.Values.GetEnumerator(); } #endregion }
David Claux | Program Manager - Exchange Web Services- Proposed as answer by David Claux - MSFT Monday, August 24, 2009 9:36 PM
- Marked as answer by gkriggs Monday, August 24, 2009 10:09 PM
Monday, August 24, 2009 9:35 PM -
Thank you for the sample code. I will give it a try.
--GregMonday, August 24, 2009 10:09 PM -
Hi David;
This code works fine with my own credentials. However, if I try to access the master category list of another mailbox it says that "The specified object was not found in the store" Do you have any idea why it is so? or is it the expected behaviour?
Many thanks
RegardsTuesday, December 13, 2011 12:08 PM -
Hi David,
your code is working fine. Can you please tell me how to add categories to MasterCategoryList.
I appreciate your help
Thanks
Shiva
Wednesday, February 20, 2013 2:17 PM -
Hi,
I ran into the error "The specified object was not found in the store" myself, but using my own mailbox. I read somewhere else, that to access the category list via EWS, at least once a custom property has to be created before on that mailbox.
So after I created a custom property using outlook, I was able to retrieve the category list from that mailbox.
Maybe that helps.
Regards
Kai
Monday, October 21, 2013 9:22 AM