Share via


In-Band Provisioning

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.

The process of provisioning a Microsoft Office Communicator client is known as in-band provisioning and requires a client to subscribe to the local user's published presence categories. An advantage of in-band provisioning is that a user can sign in to Microsoft Office Communications Server from any workstation where Office Communicator is installed. The provisioned user presence categories are tied to the identity of the signed-in user rather than a workstation identity.

An Office Communicator client does not persist a local user's presence category data locally. For this reason, an Office Communicator client must be provisioned with the local user's own presence categories when the local endpoint is registered with Office Communications Server. A local endpoint is registered with Office Communications Server after the local user provides credentials and signs in to Office Communications Server. Before an Office Communicator client is provisioned with these presence categories, the client must first publish the categories. Further updates to those categories are done on instances provisioned on the client and re-published. The category updates are provisioned on an Office Communicator client the next time that user signs in to Office Communications Server.

An Office Communicator client cannot receive self-published category data until after the client is registered on Office Communications Server. A client should not subscribe for the local user's published presence until after the OnEnable event is raised by the platform. The client is registered with Office Communications Server if the StatusCode parameter value for OnEnable is greater than or equal to zero.

In-Band Provisioning Objects

To receive a local user's self published presence categories, the client must create two objects. The first object is an instance of IUccPresentity and represents the local publishing user. The second object is an instance of IUccSubscription.

Subscription Object

A subscription object is a request on Office Communications Server for updates to categories published by a user. The subscription object allows a client to describe both whose published presence is requested and what specific categories of presence data to return in the subscription. The subscription object exposes methods to obtain newly published presence categories and updated presence categories. In addition, a local client can make a one-time request for presence category data with a query. This latter feature of the subscription object must be used to obtain the server configuration categories necessary for the client to interoperate with remote users.

A client should subscribe to the following categories:

  • "categories"
  • "containers"
  • "contacts"
  • "groups"
  • "subscribers"

A second subscription is created to Query for the "ServerConfiguration" category. This category returns a collection of URI values that are used by a local client to connect to servers implementing specific Office Communications Server roles. For information about querying for the server configuration category, see Query Office Communications Server Configuration.

For more information about creating subscriptions, see Subscribe to Category Instances.

Presentity Object

After a local client creates a subscription object, the necessary presentity is obtained with a call into CreatePresentity. The presentity object is created using an instance of UccUri returned by the URI manager (IUccUriManager). A local client can again use the same UccUri instance passed to the platform manager in the call to CreateEndpoint.

For information about creating an endpoint, see Create a Principal Endpoint.

In-Band Provisioning Events

For information about basic subscription event handling, see Receive Subscribed Categories.

Subscription Events

The OnSubscribe event is used to get the result of a subscription. If an attempt to subscribe to self-published categories is not successful, the OnSubscribe event data parameter for the StatusCode property value is negative. A client should handle this event. A failure to subscribe means that the client will not obtain in-band provisioning.

Presentity Events

These events are raised on the local user's presentity instance. For each category returned to the client from the list of categories added to the original subscription request, an OnCategoryContextAdded event is raised on the presentity. After raising the event, the client must advise for events raised by the new category context. As instances of that category context are returned to the client from Office Communications Server, an OnCategoryInstanceAdded is raised on the category context.

In-Band Provisioning Programming Pattern

The following programming pattern can be used by a custom client to create an in-band provisioning subscription and handle the resulting events:

  1. Create a subscription.
  2. Create a presentity by calling CreatePresentity on the new subscription.
  3. Advise for events raised by the new presentity.
  4. Add the in-band provisioning related categories to the new subscription.
  5. Add the new presentity to the subscription.
  6. Activate the subscription by calling Subscribe on the new subscription.
  7. Handle presentity events.
  8. Handle presentity-related category context events.

In-Band Provisioning Examples

The following examples create a subscription for categories published by the local user and handle subscription related events.

// Private class field declarations.
private UccSubscription m_SelfSubscription;
private UccSubscription m_ConfigurationQuery;
private IUccSubscriptionManager m_SubscriptionMgr;
private IUccServerConfigurationCategory m_ServerConfiguration;
private Dictionary<int, UCCPContainer> m_Containers;


// Presentity representing the self user.
private UccPresentity m_SelfPresentity;

// Subscription used to subscribe for availability/contact card of all contacts.
private IUccSubscription m_SelfSubscription;

The previous code example lists the custom application class fields that are implemented in the following code examples.

Start In-Band Provisioning Process

The following example starts the in-band provisioning process by calling application methods that wrap Unified Communications Client API interfaces for creating presentity and subscription objects.

/// <summary>
/// Method creates 2 subscriptions to self data and a subscription to contact data
/// 1: this.selfSubscription. A subscription to "categories" and "containers"
/// 2: this.selfSubscriptionForContactList. A subscription to contact and group lists
/// 3: this.contactsSubscription. A subscription to individual contact data
/// </summary>
private void StartInbandProvision()
{
    try{

        // Subscribe for "categories" and "containers" by creating a new subscription,
        // advising for subscription events, adding self presentity and category names
        // to the subscription, and calling subscribe.
        this.m_SelfSubscription = this.pr_MakeSubscription(
            this.m_SubscriptionMgr, 
            "SelfPublished", 
            "Categories and containers",
            this);

        // Create a presentity to represent self and advise for events.
        UccUri u = myUriManager.ParseUri(this.m_SelfURI);
        this.m_SelfPresentity = this.pr_MakePresentity(
            this.m_SelfSubscription, 
            u, 
            "Publisher", 
            "self", 
            this);

        this.pr_SetSubscriberContext(ref this.m_SelfPresentity, this.m_SubscribeContext);

        this.m_SelfSubscription.AddPresentity(this.m_SelfPresentity);
        this.m_SelfSubscription.AddCategoryName("categories");
        this.m_SelfSubscription.AddCategoryName("containers");
        this.m_SelfSubscription.AddCategoryName("contacts");
        this.m_SelfSubscription.AddCategoryName("groups");
        this.m_SelfSubscription.AddCategoryName("subscribers");
        this.m_SelfSubscription.Subscribe(null);

        this.m_ConfigurationQuery = this.m_SubscriptionMgr.CreateSubscription(null);
        this.m_ConfigurationQuery.AddCategoryName("ServerConfiguration");


        UccPresentity QueryPresentity = this.pr_MakePresentity(
            this.m_ConfigurationQuery,
            u,
            "Publisher",
            "self",
            this);

        this.m_ConfigurationQuery.AddPresentity(QueryPresentity);
        UCC_Advise<_IUccSubscriptionEvents>(this.m_ConfigurationQuery, this);
        this.m_ConfigurationQuery.Query(null);
    
    }
    catch (COMException e)
    {
        // SelfSubscription failed. Raise an event to indicate sign in failed.
        SigninDone(false);
    }
    catch (NullReferenceException ne)
    {
        // SelfSubscription failed. Raise an event to indicate sign in failed.
        SigninDone(false);
    }
}

The following example creates a new instance of UccSubscription with a corresponding IUccContext. The example method advises for events raised by the new UccSubscription object to be handled by the application class.

/// <summary>
/// Creates a new subscription object with associated
/// metadata context
/// </summary>
/// <param name="pSubScriptionManager">endpoint as subscription manager</param>
/// <param name="pSubContextPropertyName">context property name</param>
/// <param name="pSubContext">context value</param>
/// <param name="pEventSink">Class instance implementing event handler for subscription events</param>
/// <returns>new IUccSubscription with context</returns>
private UccSubscription pr_MakeSubscription(
    IUccSubscriptionManager pSubScriptionManager,
    string pSubContextPropertyName,
    string pSubContext,
    _IUccSubscriptionEvents pEventSink)
{
    UccSubscription returnValue = null;
    if (pSubScriptionManager == null)
    {
        throw new ArgumentNullException("pSubscriptionManager", "Subscription mananger cannot be null");
    }
    if (pEventSink == null)
    {
        throw new ArgumentNullException("pEventSink", "Event Sink cannot be null");
    }
    try
    {
        UccContext subContext = new UccContextClass();
        if (pSubContextPropertyName.Length > 0 && pSubContext.Length > 0)
        {
            subContext.AddNamedProperty(pSubContextPropertyName, pSubContext);
        }
        returnValue = pSubScriptionManager.CreateSubscription(subContext);
    
        UCC_Advise<_IUccSubscriptionEvents>(returnValue, pEventSink);
    }
    catch (COMException)
    {}
    return returnValue;
}

The following example creates a new instance of UccPresentity with a corresponding IUccContext object, and advises for presentity events.

/// <summary>
/// Creates a new presentity instance to be added to subscription
/// </summary>
/// <param name="pSubscription">Subscription presentity factory object</param>
/// <param name="pPublisher">Publishing Uri</param>
/// <param name="pContextKey">meta data context key</param>
/// <param name="pContextValue">metadata context value</param>
/// <param name="pEventSink">Class instance implementing presentity event handlers</param>
/// <returns>new Presentity</returns>
private UccPresentity pr_MakePresentity(
    UccSubscription pSubscription,
    UccUri pPublisher,
    string pContextKey,
    string pContextValue,
    _IUccPresentityEvents pEventSink)
{
    UccPresentity returnValue = null;
    if (pSubscription == null)
    {
        throw new ArgumentNullException("pSubscription", "Subscription cannot be null");
    }
    if (pPublisher == null)
    {
        throw new ArgumentNullException("pPublisher", "Publishing Uri cannot be null");
    }
    try
    {
        UccContext subContext = new UccContextClass();
        if (pContextKey.Length > 0 && pContextValue.Length > 0)
        {
            subContext.AddNamedProperty(pContextKey, pContextValue);
        }
        returnValue = pSubscription.CreatePresentity(pPublisher, subContext);

       // Advise for presentity events that are raised on the platform when Office Communications Server
       // returns published categories.
        UCC_Advise<_IUccPresentityEvents>(returnValue, pEventSink);
    }
    catch (COMException)
    { }
    return returnValue;
}

The returned UccPresentity is added to the new IUccSubscription object created in the previous example.

Advising for Category Context Events

The following example advises for category context events that are raised by the platform when Office Communications Server returns categories previously published by the presentity added to the subscription.

void _IUccPresentityEvents.OnCategoryContextAdded(
        UccPresentity pEventSource,
        UccCategoryContextEvent pCategoryCtxt)
{
    // Advise for _IUccCategoryContextEvents on any category context that appears so that
    // category instances corresponding to the category context are included. 
    // Since the "categories" category is included in the subscription, the OnCategoryContextAdded
    // event for all the categories for the individual user are included, for example: "contactCard" and
    // "state".
    UCC_Advise<_IUccCategoryContextEvents>(
        pCategoryCtxt.CategoryContext, 
        this);
}

Handling Category Context Events

The following example handles the category context events associated with the presentity representing the local user. The example only processes contacts, groups, and containers. A custom client application should handle all of the categories in the switch structure.

/// <summary>
/// Handles category context events for any presentity whose events were advised for
/// in this class instance.
/// </summary>
/// <param name="pCategoryCtx"></param>
/// <param name="pCategory"></param>
void _IUccCategoryContextEvents.OnCategoryInstanceAdded(
    IUccCategoryContext pCategoryCtx, 
    UccCategoryInstanceEvent pCategory)
{
    try
    {
        IUccCategoryInstance ci = pCategory.CategoryInstance;

        StringComparer strComparer = StringComparer.Create(
            System.Globalization.CultureInfo.CurrentCulture,
            true);
        IUccCategoryContext catContext = pCategory.CategoryInstance.CategoryContext;
        
        switch (pCategory.CategoryInstance.CategoryContext.Name.ToLower().Trim())
        {
            case "contacts":
                // A category instance with category context name "contacts" represents
                // a contact. Cast the category instance to IUccContact to get the
                // IUccContact object.

                UCC_Advise<_IUccCategoryInstanceEvents>(
                    pCategory.CategoryInstance, 
                    this);


                // For clients interested in maintaining a local client's contact list, the
                // following code pattern should be followed:

                //1) Cast category instance to UccContact to expose Uri property.
                UccContact addedContact = pCategory.CategoryInstance as UccContact;

                //2) Create a presentity for this contact.
                UccPresentity presentity = m_ContactsSubscription.CreatePresentity(addedContact.Uri, null);

                //3) Add the new presentity to a subscription object whose presentity collection contains
                // a presentity instance for each contact in the contact list.
                m_ContactsSubscription.AddPresentity(presentity);

                //4) Issue subscribe request for the new contact.
                m_ContactsSubscription.Subscribe(null);


                if (this.m_ContactManager != null)
                {
                     // Custom application class, UCCPContact handles the presentity events raised when Office Communications Server responds to the subscription
                     // request generated in UCCPPlatformManager (this).

                     // For a code listing of the Contact class, see topic: Sample Contact Presence Handling Class.
                    Contact newContact = new Contact(addedContact, presentity);
                }

                break;
            case "groups":
                // A category instance with category context name "groups" represents
                // a contact group. Cast the category instance to IUccGroup to get the
                // IUccGroup object.
                    UCC_Advise<_IUccCategoryInstanceEvents>(
                    pCategory.CategoryInstance, 
                    this);

                IUccGroup addedGroup = pCategory.CategoryInstance as IUccGroup;

                if (this.m_ContactManager != null)
                {
                    // The Group type is a class defined in Group.cs. It wraps the functionality
                    // of the IUccGroup interface.
                    // Create a new Group object.
                    UCCPGroup newGroup = new UCCPGroup(addedGroup);//, this.contactsSubscription);
                    this.m_ContactManager.AddToGroupDict(newGroup);
                }
                break;
            case "subscribers":
                break;
            case "categories":
                break;
            case "state":
                break;
            case "calendarData":
                break;
            case "routing":
                break;
            case "legacyInterop":
                break;
            case "alerts":
                break;
            case "device":
                break;
            case "otherOptions":
                break;
            case "services":
                break;
            case "userInformation":
                break;
            case "userProperties":
                break;
            case "contactCard":
                break;
            case "containers":
                try
                {
                    // A subscription to the containers category must be created if a local  
                    // user is to publish updates to previously published enhanced presence categories.
                    // The collection of containers holds previously published category instances.
                    this._cmm = pCategoryCtx as IUccContainerMembershipManager;

                    UCCPContainer _containerClass = new UCCPContainer(pCategory.CategoryInstance as IUccContainer);

                    // Add container class wrapper instance to application cache for later re-publishing.
                    if (this.m_Containers.ContainsKey(pCategory.CategoryInstance.InstanceId) == false)
                    {
                        m_Containers.Add(pCategory.CategoryInstance.InstanceId, _containerClass);
                    }

                    UCC_Advise<_IUccCategoryInstanceEvents>(
                        pCategory.CategoryInstance,
                        this);
                    }
                catch (InvalidCastException ice)
                {
                    MessageBox.Show(
                        "Invalid Cast exception on Category Instance Added: " + ice.Message);
                }

                break;
            case "serverconfiguration":

                m_ServerConfiguration = pCategory.CategoryInstance as IUccServerConfigurationCategory;
                break;

            default:
                break;
        }

    }
    catch (COMException e)
    {
        MessageBox.Show(
            "sampleUCCPClient.PlatformManager On Category Instance Added: COM Exception. Category: " +
            pCategory.CategoryInstance.CategoryContext.Name +
            e.Message);
    }
}

See Also

Concepts

Query Office Communications Server Configuration
Publishing and Subscribing
Subscribe to Category Instances
Query Category Instances
Create a Principal Endpoint