none
Edit Master Category List in Exchange 2010 via EWS?

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.
    --Greg

    Monday, 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


    Regards

     

     

    Tuesday, 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