Receive Subscribed Categories

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

Receiving subscribed category data involves handling two classes of events. The first class of events is raised by the subscription request object itself. The second class of events is raised by presentity instances representing the subscribed users. Note that you can “batch” multiple presentities into a single subscription. That is, you can add more than one presentity instance to the collection of presentites exposed by a subscription object.

The presentity instances in the collection are the basis for all further subscribed category processing. A custom client can instantiate a new application class for each presentity added to the subscription. The responsibility of this application class is to handle the events raised when Office Communications Server returns categories specific to a presentity. These presentity events expose properties whose values provide the subscribed categories.

Subscription Events

Events of this type are defined in the _IUccSubscriptionEvents interface. The OnSubscribe event has three purposes.

  1. The event allows a client to determine the success or failure of a subscription request
  2. The event marks the point at which Office Communications Server has returned a complete set of subscribed categories. Subsequent updates to subscribed categories continue to be returned in presentity events.
  3. The event exposes a collection of presentity instances representing users whose enhanced presence categories are subscribed to. Iterating on the presentity collection and calling GetOperationInfo with each presentity provides the individual subscribe request status information.

The IUccSubscriptionEvent type contains status information about the subscription request itself. The Presentities property of the interface is a collection of IUccPresentity types. Each presentity in the collection represents the publisher of the category data of interest.

Important

OnSubscribe is raised once for each of the presentities added to the subscription upon the completion of a subscription request. A subscription request is completed when all of a given presentities subscribed categories are returned as presentity events. For example: If your application is to subscribe to the enhanced presence of every member of the local user’s contact list, you issue a subscription request containing a batch of contact presentities when you handle OnSubscribe where the subscription completed is the local user’s subscription to the contacts category context.

The following example handles the OnSubscribe event.

        /// <summary>
        /// Handles event raised when Office Communications Server has completed a 
        /// subscription request for a member of the presentity collection on the subscription.
        /// </summary>
        /// <param name="pSubscription">UccSubscription Original subscription request</param>
        /// <param name="pEventInfo">UccSubscriptionEvent subscription status</param>
        void _IUccSubscriptionEvents.OnSubscribe(
            UccSubscription pSubscription,
            UccSubscriptionEvent pEventInfo)
        {
            try
            {
                // Presentity is local user. Subscription  to ″contacts″
                if (Object.ReferenceEquals(pSubscription, this.m_SelfSubscription))
                {
                    // Get the operation info for the presentity collection member that is the local user. 
                    // A self-subscription contains a presentity collection with a single member, 
                    // otherwise the subscription is a batch subscription with multiple instances of IUccPresentity.
                    IUccOperationProgressEvent opEvent = pEventInfo.GetOperationInfo(m_SelfPresentity);
                    if (opEvent.IsComplete)
                    {
                        if (opEvent.StatusCode >= 0)
                        {
                            // Raise an event to indicate sign in completed successfully

                            //issue batch subscribe request for new contacts
                            m_ContactsSubscription.Subscribe(null);
 
                        }

                    }
                }
                else if (Object.ReferenceEquals(pSubscription, this.m_ContactsSubscription))
                {
                    foreach (UccPresentity p in pEventInfo.Presentities)
                    {
                        if (
                            pEventInfo.GetOperationInfo(p).IsComplete == true 
                            && pEventInfo.GetOperationInfo(p).StatusCode >= 0)
                        {
                            //Custom client can instantiate a presentity class to handle events
                            //raised on the presentity when Office Communications Server returns
                            //enhanced presence categories published by the user represented by
                            //the presentity.

                        }

                    }
                }
            }
            catch (COMException e)
            {

                Utilities.HandleException<COMException>(
                    "sampleUCCPClient.Contact On subscribe: COM Exception. ",
                    e,
                    this.m_ShowMessage);
            }
        }

The following example handles the OnQuery event.

void _IUccSubscriptionEvents.OnQuery(
     UccSubscription source, 
     IUccSubscriptionEvent eventData)
{
    foreach (IUccPresentity p in eventData.Presentities)
    {
        if (
                eventData.GetOperationInfo(p).IsComplete == true 
                && eventData.GetOperationInfo(p).StatusCode >= 0)
        {
                UCC_Unadvise<_IUccPresentityEvents>(p, this);

                MessageBox.Show("Query for " + p.Uri.User + " succeeded.");
        }
    }
    UCC_Unadvise<_IUccSubscriptionEvents>(source, this);

}

Important

OnQuery is raised by the platform after Office Communications Server has completed a query request and returned all queried categories as presentity events. For example: A client queries for serverConfiguration. OnQuery is raised after the instance of serverConfiguration has been received by the client.

Presentity Events

The other event type is related to the subscribed or queried data, namely category instances. Events of this type are defined in the _IUccPresentityEvents, _IUccCategoryContextEvents, and _IUccCategoryInstanceEvents interfaces. The application presentity event class discussed in the previous example must implement the callback methods exposed by the _IUccPresentityEvents interface. Handling the events raised by this interface allows a client to advise for the category related events raised when Office Communications Server returns category data for a specific presentity.

The following example handles the two possible presentity events:

Query can only generate the OnCategoryContextAdded event. To extend the example described previously, each presentity added to the subscription generates a presentity event (contactCard).

Each category context object is returned as the event data argument of OnCategoryContextAdded contains a CategoryContext property. To receive category context events such as OnCategoryInstanceAdded, you must advise for category context events using the CategoryContext property as the event source.

void _IUccPresentityEvents.OnCategoryContextAdded(
    UccPresentity pEventSource,
    UccCategoryContextEvent pCategoryCtxt)
{
    try
    {
        IUccCollection publishedCategories = pEventSource.CategoryContexts;
        String contextName = pCategoryCtxt.CategoryContext.Name.ToLower().Trim();
        if (contextName == "contactcard")
        {
            //Advise for category context events to get notified when
            //corresponding instances are published
            UCC_Advise<_IUccCategoryContextEvents>(
               pCategoryCtxt.CategoryContext, 
               this);
        }
    }
    catch (COMException e)
    {
        MessageBox.Show(
            "UCCPPresentityEvents. Presentity Events, On CategoryContext Added: COM Exception. "
            + e.Message);
    }
}
void _IUccPresentityEvents.OnCategoryContextRemoved(
    UccPresentity pEventSource,
    UccCategoryContextEvent pEventData)
{
    UCC_Unadvise<_IUccCategoryContextEvents>(
        pEventData.CategoryContext,
        this);
}

In the previous example, the client advised for category context events in the presentity OnCategoryContextAdded callback method. This is necessary if the client is to receive category instance data. In other words, to receive a subscribed or queried presentity's actual Contact Card information or aggregated state, you must handle the OnCategoryInstanceAdded event. This category context event along with OnCategoryInstanceRemoved and OnCategoryInstanceValueModified represents all category instance events. These events are raised when a queried or subscribed presentity publishes additions, changes, or deletions to their presence categories.

The example OnCategoryInstanceAdded method is written to handle two strongly typed category instances and any generic category instance. When the category instance is one of the well-known and strongly typed category instances, the IUccCategoryInstance interface received can be cast to the derived interface. In this example, a contact instance and group instance are specifically handled.

void _IUccCategoryContextEvents.OnCategoryInstanceAdded(
            IUccCategoryContext catCtxt, 
            IUccCategoryInstanceEvent catInstEvt)
{
    string s;
    IUccCategoryInstance cInst = catInstEvt.CategoryInstance;
    if (catCtxt.Name == "contacts")
    {
        UccContact contact = cInst as UccContact;
        UCC_Advise<_IUccContactEvents>(contact, this);
    }
    else if (catCtxt.Name == "groups")
    {
        IUccGroup group = cInst as IUccGroup;
        UCC_Advise<_IUccGroupEvents>(group, this);
    }
    else
    {
        UCC_Advise<_IUccCategoryInstanceEvents>(cInst, this);
    }
}

void _IUccCategoryContextEvents.OnCategoryInstanceRemoved(
       IUccCategoryContext catCtxt, IUccCategoryInstanceEvent catInstEvt)
{
    IUccCategoryInstance cInst = catInstEvt.CategoryInstance;
    UCC_Unadvise<_IUccCategoryInstanceEvents>(cInst, this);
}
void _IUccCategoryInstanceEvents.OnCategoryInstanceValueModified(
    IUccCategoryInstance pCategoryInstance, 
    object pEventData)
{
    StringComparer strComparer = StringComparer.Create(
    System.Globalization.CultureInfo.CurrentCulture,
    true);

    //process the updated "contactCard" category instance
    if (strComparer.Compare(
        pCategoryInstance.CategoryContext.Name,
        "contactCard") != 0)
    {
        //UCCPPresentityEvents class only handles "contactCard" events. 
        return;
    }

    IUccPresenceContactCardInstance card = pCategoryInstance as IUccPresenceContactCardInstance;

    if (card == null)
    {
        return;
    }

    if (pCategoryInstance.Presentity.IsSelf == true)
    {
        return;
    }
    IUccPresenceContactCardIdentity cardID = card.Identity as IUccPresenceContactCardIdentity;
    if (cardID != null)
    {
        MessageBox.Show("New Display Name " + cardID.DisplayName);
    }
    if (card.Phones.Count == 0)
    {
        return;
    }

    foreach (IUccPresenceContactCardPhone phone in card.Phones)
    {
        if (phone.Url.ToLower().Contains("tel:"))
        {
            MessageBox.Show("New telephone " + phone.Url);
        }
    }
}

For strongly typed category instances, an application must also handle any type-specific events. For example, for an IUccContact object, the application must also handle _IUccContactEvents. Not all strongly typed category instances raise additional events beyond the generic ones. For example, an IUccPresenceStateInstance object does not raise any additional events.

Presentity Events Class Handler Example

The following example is a complete class listing for an application class that handles presentity, category context, and category instance events. For the sake of brevity, the example handles only categories of type contactCard.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.UccApi;
using System.Reflection;
using UccpAppComponents;



namespace UccpAppComponents
{
    public class UCCPPresentityEvents: 
        _IUccPresentityEvents, 
        _IUccCategoryContextEvents,
        _IUccCategoryInstanceEvents,
        IDisposable
    {


        #region private fields
        private IUccPresentity m_Presentity;
        private string m_SubscriptionType = string.Empty;
        private Boolean m_Disposed = false;
        #endregion

        #region constructors
        public UCCPPresentityEvents(IUccPresentity pPresentity, string pSubscriptionType)
        {
            if (pPresentity == null)
            { 
                throw new ArgumentNullException("pPresentity","Presentity cannot be null");
            }
            if (pSubscriptionType == null || pSubscriptionType == string.Empty)
            {
                this.m_SubscriptionType = "query";
            }
            this.m_Presentity = pPresentity;
            UccApiUtilities.Advise<_IUccPresentityEvents>(this.m_Presentity, this);

        }
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }
        private void Dispose(Boolean disposing)
        {
            if (!this.m_Disposed)
            {
                if (disposing)
                {
                    UccApiUtilities.Unadvise<_IUccPresentityEvents>(this.m_Presentity, this);
                }
                this.m_Disposed = true;
            }
        }

        #endregion
        #region _IUccPresentityEvents Members

        void _IUccPresentityEvents.OnCategoryContextAdded(
            UccPresentity pEventSource,
            UccCategoryContextEvent pCategoryCtxt)
        {
            try
            {
                IUccCollection publishedCategories = pEventSource.CategoryContexts;
                String contextName = pCategoryCtxt.CategoryContext.Name.ToLower().Trim();
                if (contextName == "contactcard")
                {
                    //Advise for category context events to get notified when
                    //corresponding instances are published
                    UccApiUtilities.Advise<_IUccCategoryContextEvents>(pCategoryCtxt.CategoryContext, this);
                }
            }
            catch (COMException e)
            {
                MessageBox.Show(
                    "UCCPPresentityEvents. Presentity Events, On CategoryContext Added: COM Exception. "
                    + e.Message);
            }
        }

        void _IUccPresentityEvents.OnCategoryContextRemoved(
            UccPresentity pEventSource,
            UccCategoryContextEvent pEventData)
        {
            UccApiUtilities.Unadvise<_IUccCategoryContextEvents>(pEventData.CategoryContext, this);

        }

        #endregion

        #region _IUccCategoryContextEvents Members

        void _IUccCategoryContextEvents.OnCategoryInstanceAdded(
            IUccCategoryContext pCategoryCtxt, 
            UccCategoryInstanceEvent pCategoryInstanceEvent)
        {
            try
            {
                // Advise for category instance events to get notification when this
                // instance is modified and process the current category instance
                if (pCategoryInstanceEvent.CategoryInstance != null)
                {

                    UccApiUtilities.Advise<_IUccCategoryInstanceEvents>(pCategoryInstanceEvent.CategoryInstance, this);
                }

            }
            catch (COMException e)
            {
                MessageBox.Show(
                    "UCCPPresentityEvents. Presentity Events, On CategoryInstance Added: COM Exception. "
                    + e.Message);
            }
        }

        void _IUccCategoryContextEvents.OnCategoryInstanceRemoved(
            IUccCategoryContext pEventSource,
            UccCategoryInstanceEvent pEventData)
        {
            UccApiUtilities.Unadvise<_IUccCategoryInstanceEvents>(pEventData.CategoryInstance, this);
        }

        #endregion

        #region _IUccCategoryInstanceEvents Members

        void _IUccCategoryInstanceEvents.OnCategoryInstanceValueModified(
            IUccCategoryInstance pCategoryInstance, 
            object pEventData)
        {
            StringComparer strComparer = StringComparer.Create(
            System.Globalization.CultureInfo.CurrentCulture,
            true);

            //process the updated "contactCard" category instance
            if (strComparer.Compare(
                pCategoryInstance.CategoryContext.Name,
                "contactCard") != 0)
            {
                //UCCPPresentityEvents class only handles "contactCard" events. 
                return;
            }

            IUccPresenceContactCardInstance card = pCategoryInstance as IUccPresenceContactCardInstance;

            if (card == null)
            {
                return;
            }

            if (pCategoryInstance.Presentity.IsSelf == true)
            {
                return;
            }
            IUccPresenceContactCardIdentity cardID = card.Identity as IUccPresenceContactCardIdentity;
            if (cardID != null)
            {
                MessageBox.Show("New Display Name " + cardID.DisplayName);
            }
            if (card.Phones.Count == 0)
            {
                return;
            }

            foreach (IUccPresenceContactCardPhone phone in card.Phones)
            {
                if (phone.Url.ToLower().Contains("tel:"))
                {
                    MessageBox.Show("New telephone " + phone.Url);
                }
            }
            if (this.m_SubscriptionType == "query")
            {
                this.Dispose();
            }
        }

        #endregion
    }
}

See Also

Concepts

Publish Category Instances
Subscribe to Category Instances
Query Category Instances