Programming Enhanced Presence Schemas: Creating Category Instances (Part 2 of 3)

Summary:   When you publish an enhanced presence category, you must create the XML string of a given category instance. This article discusses how to programmatically generate this string by instantiating a common language runtime (CLR) class of the XSD type as defined in a unified communications enhanced presence schema.

This article is the second installment of a three-part series of articles. For information about part 1 and part 3, see Additional Resources.

Applies to:   Microsoft Lync 2010 | Microsoft Office Communicator 2007 R2

Published:   February 2011 | Provided by:   Kurt De Ding, Microsoft | About the Author

Contents

  • Introduction

  • Creating the Visual Studio Project

  • Creating a CLR Object of an Enhanced Presence Category Schema Type

  • Setting Presence Data on Enhanced Presence Category Instances

  • Testing the Application

  • Conclusion

  • Additional Resources

Introduction

Publishing a particular presence category instance requires you to provide a well-formed XML string that represents the value of the category instance that you want to publish. Manually creating this XML string can be tedious and can introduce errors.

In this article, part 2 of a three-part series, you learn how to programmatically create the well-formed XML string that represents an enhanced presence category instance value. The process involves using the Microsoft.Rtc.Sdk.Categories.DLL assembly that was created in Programming Enhanced Presence Schemas: Creating .NET Framework Assemblies from Schemas (Part 1 of 3), and the System.Xml.Serialization .NET Framework namespace to complete these tasks:

  1. Instantiate a common language runtime (CLR) class from the Microsoft.Rtc.Sdk.Categories.DLL assembly. The CLR class corresponds to an XML schema definition (XSD) type that defines the specified category instance value.

  2. Assign the category instance value by setting the properties of the type-safe CLR objects.

  3. Serialize the CLR object to obtain the XML string of the category instance value. The resulting XML string is well-formed and ready for publication.

The following sections show how to implement these tasks in a Microsoft Unified Communications Managed API (UCMA) 2.0 Core application.

Creating the Visual Studio Project

To create the project

  1. Start Microsoft Visual Studio 2008 development system, click File and then click New Project. The New Project dialog box appears.

  2. In the New Project dialog box, select Visual C# as the project type and Windows Forms Application as the template.

  3. In the Name text box, type PresencePublisher for the project name, and then click OK. The PresencePublisher - Microsoft Visual Studio window appears.

  4. In the Solution Explorer - PresencePublisher pane, right-click References and then select Add Reference.

  5. Select the Browse tabbed page in the Add Reference control, and then find Microsoft.Rtc.Sdk.Categories.DLL (the enhanced presence schemas assembly that are created in part 1 of this series). Click OK.

Creating a CLR Object of an Enhanced Presence Category Schema Type

After comparing the three tasks appearing at the beginning of this article that are used to create a CLR object of an enhanced presence category schema type, the second task must deal with operations that are type-specific. The first and the third tasks involve operations common to all the category types. In order to reuse code, the common operations are encapsulated by using a base class and the type-specific operations are handled in the subclasses that are derived from the base class.

In the code examples that follow, PresenceCategorySchemaObject is the base class that implements the common operations. PresenceNoteSchemaObject and PresenceUserStateSchemaObject are two subclasses that handle type-specific features that apply to the noteType and userState types. This type of code separation not only promotes code reuse, but also makes the illustration more modular and easier to follow.

The following steps and code show how to implement the PresenceCategorySchemaObject class.

To create a CLR object of an enhanced presence category schema type

  1. Open the PresencePublisher project in Visual Studio.

  2. Add a C# class file to this project, and then name this file PresenceCategroySchemaObject.cs.

  3. Copy the following C# code and paste it to the Code Editor of the PresenceCategroySchemaObject.cs class:

    using System.Xml;
    using System.Xml.Serialization;
    using System.IO;
    using Microsoft.Rtc.Sdk.Categories;
    
  4. Add an instance variable, _objCategory, to the PresenceCategorySchemaObject class definition:

    namespace PresencePublisher
    {
        public class PresenceCategorySchemaObject
        {
            protected object _objCategory = null;
    
        }
    }
    

    The _objCategory instance variable will be used to hold an instance of an enhanced presence category schema object. This instance variable is declared as protected so that the derived classes can access it.

  5. Add the following constructor definition to the PresenceCategorySchemaObject class:

            public PresenceCategorySchemaObject(Type type)
            {
                try
                {
                    _objCategory = type.Assembly.CreateInstance(type.FullName);
                }
                catch (Exception ex)
                {
                    // Handle any exceptions.
                }
            }
    

    This constructor instantiates a presence category type from the hosting assembly of the given Type instance (type.Assembly). An exception of the System.MissingMethodException type is thrown if the type instance used in the previous code is an abstract type. For example, in the enhanced presence state schema, stateType is an abstract type. Any attempt to create an instance of this kind throws the exception. To create an enhanced presence state object, you must use one of the following concrete state types that are derived from the following stateType base type:

    • userState (<state type=”userState”>)

    • machineState (<state type=”machineState”>)

    • calendarState (<state type=”calendarState”>)

    • phoneState (<state type=”phoneState”>)

    • aggregateState (<state type=”aggregateState”>)

    • aggregatemachineState (<state type=”aggregateMachineState”>)

  6. Add the following ToXml member method to the PresenceCategorySchemaObject class definition:

        public string ToXml()
        {
            if (_objCategory == null)
                return null;
    
            string strXml = null;
            Type serializedType = _objCategory.GetType();
    
            // Ensure that the presence state instance is serialized
            // into <state xsi:type="userState" ...>...</state>
            // instead of <userState ...>...</userState> or something similar.
            if (_objCategory is Microsoft.Rtc.Sdk.Categories.State.stateType)
            {
                // All the presence state types will be of the stateType base type.
                serializedType = typeof(Microsoft.Rtc.Sdk.Categories.State.stateType);
            }
    
            // Serialize the _objCategory object into an XML string.
            try
            {
                StringWriter sw = new StringWriter();
    
                XmlWriterSettings setting = new XmlWriterSettings();
                setting.OmitXmlDeclaration = true;
                setting.NewLineOnAttributes = true;
                setting.IndentChars = "   ";
                setting.Indent = true;
                XmlWriter xw = XmlWriter.Create(sw, setting);
    
                XmlSerializer serializer = new XmlSerializer(serializedType);
                serializer.Serialize(xw, _objCategory);
    
                xw.Flush();
                xw.Close();
    
                sw.Flush();
                sw.Close();
    
                strXml = sw.ToString();
            }
            catch (Exception ex)
            {
                 // Handle any exceptions.
            }
            return strXml;
            }
    

The ToXml method uses the System.Xml.Serialization namespace to serialize the _objCategory object. It returns the XML string of the enhanced presence category instance value. The properties of this enhanced presence category instance are set by using a type-specific subclass. The resultant XML string can be submitted in a publication request. In UCMA 2.0 Core, this XML string is a part of the input to the BeginPublishPresence method on a LocalOwnerPresence object. The XmlWriterSettings type is used to specify the XML format of the output. The XmlSerializer object is used to perform the serialization.

The name of a serialized XML element is determined by the definition of the underlying XML schema. For example, the presence note schema defines a <note> element of noteType. To serialize a presence note object, the serialized type must be of noteType. Similarly, the enhanced presence state schema defines a <state> element to be a stateType type. Therefore, to obtain a <state> XML element, the serialized type must be a stateType. However, stateType is an abstract type; any of its instances are created from one of its concrete subtypes. To serialize an enhanced presence state object, the serialized type must be set to their base type, namely, stateType. If userState (for example, a subtype of stateType) is used instead, the serialization produces a spurious <userState> XML element.

Setting Presence Data on Enhanced Presence Category Instances

To set presence data on enhanced presence category instances

  1. Add a C# class to the Visual Studio project that you created earlier, and then name the class file PresenceUserStateSchemaObject.cs. An instance of this kind is used to set the availability and activity properties on a userState category instance. For more information about the availability and activity of a presence state, see Unified Communications Enhanced Presence Schema Reference (2007 R2 Release).

  2. Copy the following statements into the new class, replacing the default class definition in the Visual Studio Code Editor:

        public class PresenceUserStateSchemaObject : PresenceCategorySchemaObject
        {
            public PresenceUserStateSchemaObject(uint availability, string activity, string token)
                : base(typeof(Microsoft.Rtc.Sdk.Categories.State.userState))
            {
                try
                {
                    // The availability property is defined in the stateType type, the 
                    // base type that userState is derived from. The following
                    // type casting is necessary to access such properties.
                    Microsoft.Rtc.Sdk.Categories.State.stateType objState =
                        _objCategory as Microsoft.Rtc.Sdk.Categories.State.stateType;
    
                    // When you set the availability property, you must also
                    // set the availabilitySpecified property to true. This
                    // programming pattern applies to other properties (X) 
                    // that have the accompanying XSpecified Boolean flag.
                    objState.availability = availability;
                    objState.availabilitySpecified = true;
    
                    Microsoft.Rtc.Sdk.Categories.State.activityType objActivity =
                        new Microsoft.Rtc.Sdk.Categories.State.activityType();
                    objActivity.token = token;
    
                    // According to the enhanced presence state schema, 
                    // the activity can have a locale-specific activity string.
                    // The locale is specified by using the LCID property. 
                    // For the U.S. English locale, the LCID is 1033.
                    Microsoft.Rtc.Sdk.Categories.State.LCIDType lcidType =
                        new Microsoft.Rtc.Sdk.Categories.State.LCIDType();
                    lcidType.Value = activity;
                    lcidType.LCID = 1033;
                    lcidType.LCIDSpecified = true;
                    objActivity.custom =
                        new Microsoft.Rtc.Sdk.Categories.State.LCIDType[] { lcidType };
    
                    objState.activity =
                        new Microsoft.Rtc.Sdk.Categories.State.activityType[] { objActivity };
                }
                catch (Exception ex)
                {
                    // Handle any exceptions.
                }
            }
        }
    

    The PresenceUserStateSchemaObject class is derived from the PresenceCategorySchemaObject class, and it inherits all of its non-private features. After you instantiate PresenceUserStateSchemaObject and set the availability number and the activity string or token, you can call ToXml on the object to produce a <state xsi:type="userState"> element. This element is populated with the availability and activity values that are passed in to the PresenceUserStateSchemaObject class constructor.

    When you set a value on the property X of an integer type, you should also set the corresponding XSpecified Boolean flag to true because it is set to false by default. The newly set X property value remains unspecified when the Boolean flag is false. In the previous code block, X is the availability and the lcidType.LCID properties.

  3. Add another class to the Visual Studio project, and then name the class file PresenceNoteSchemaObject.cs. This process is used to set a personal note.

  4. Copy the following statements, replacing the default class definition in the Code Editor:

    public class PresenceNoteSchemaObject : PresenceCategorySchemaObject
    {
        public PresenceNoteSchemaObject(string value, string type) 
                : base(typeof(Microsoft.Rtc.Sdk.Categories.Note.noteType))
        {
            try
            {
                Microsoft.Rtc.Sdk.Categories.Note.noteType objNote =
                    _objCategory as Microsoft.Rtc.Sdk.Categories.Note.noteType;
    
                Microsoft.Rtc.Sdk.Categories.Note.noteTypeBody body =
                    new Microsoft.Rtc.Sdk.Categories.Note.noteTypeBody();
                body.type = type;
                body.Value = value;
                objNote.body = new Microsoft.Rtc.Sdk.Categories.Note.noteTypeBody[] { body };
            }
            catch (Exception ex)
            {
                // Handle any exceptions.
            }
        }
    }
    

    The PresenceUserStateSchemaObject class is derived from the PresenceCategorySchemaObject class, and it inherits all of its non-private features. After you instantiate PresenceUserStateSchemaObject and set the availability number and the activity string or token, you can call ToXml on the object to produce a <state xsi:type="userState"> element. This element is populated with the availability and activity values that are passed in to the PresenceUserStateSchemaObject class constructor.

    When you set a value on property X of an integer type, you should also set the corresponding XSpecified Boolean flag to true because it is set to false by default. The newly set X property value remains unspecified when the Boolean flag is false. In the previous code block, X is the availability and the lcidType.LCID properties.

  5. Add another class to the Visual Studio project, and then name the class file PresenceNoteSchemaObject.cs. This process is used to set a personal note.

  6. Copy the following statements, replacing the default class definition in the Code Editor:

    public class PresenceNoteSchemaObject : PresenceCategorySchemaObject
    {
        public PresenceNoteSchemaObject(string value, string type) 
                : base(typeof(Microsoft.Rtc.Sdk.Categories.Note.noteType))
        {
            try
            {
                Microsoft.Rtc.Sdk.Categories.Note.noteType objNote =
                    _objCategory as Microsoft.Rtc.Sdk.Categories.Note.noteType;
    
                Microsoft.Rtc.Sdk.Categories.Note.noteTypeBody body =
                    new Microsoft.Rtc.Sdk.Categories.Note.noteTypeBody();
                body.type = type;
                body.Value = value;
                objNote.body = new Microsoft.Rtc.Sdk.Categories.Note.noteTypeBody[] { body };
            }
            catch (Exception ex)
            {
                // Handle any exceptions.
            }
        }
    }
    

The PresenceNoteSchemaObject class is derived from the PresenceCategorySchemaObject class and inherits all of its non-private features. After this class is instantiated and its body property is set, calling ToXml on the object produces a <note> element that contains a specification of the <body> child element. Office Communicator 2007 R2 supports two kinds of presence note message—a personal note or Out of Office note. For the former, the type parameter must be “personal”. For the latter, the type parameter must be “OOF”. The value parameter can be any string for the message of the presence note.

Now that we have finished implementing the PresenceUserStateSchemaObject and PresenceNoteSchemaObject classes, we should examine how they work by writing a test application.

Testing the Application

To test the application

  1. In Visual Studio, double-click the Form1 [Design] panel to generate an empty event handler (Form1_Load).

  2. Replace the event handler definition with the following code:

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                // Create a userState type instance to set a user state 
                // that has an availability number of 9500, an activity string
                // of "Some activity", and an activity token of "in a meeting."
                PresenceUserStateSchemaObject objState =
                    new PresenceUserStateSchemaObject(
                        9500,
                        "Some activity",
                        "in-a-meeting");
    
                // Produce the XML string representation of the previous userState
                // category instance value.
                string strState = objState.ToXml();
                MessageBox.Show(strState);
    
                // Create a personal presence note category instance that contains a 
                // message of "Some personal note". The second input value, 
                // "personal", specifies the note type.
                PresenceNoteSchemaObject objNote = new PresenceNoteSchemaObject(
                    "Some personal note",
                    "personal");
    
                // Produce the XML string representation of the previous note
                // category instance value.
                string strNote = objNote.ToXml();
                MessageBox.Show(strNote);
    
            }
            catch (Exception ex)
            {
                // Handle any exceptions.
            }
        }
    
  3. In Visual Studio, press F5 to build and run the project. When the form is loaded successfully, the following results appear in two MessageBox dialog boxes. The following illustration shows the serialized <e> element of the userState type.

    Hh243702.SchemaP2Figure1(en-us,office.14).jpg

    The next illustration shows the <note> element of the personalNote type.

    Hh243702.SchemaP2Figure2(en-us,office.14).jpg

Conclusion

In this article, you learned how to use an enhanced presence schema object assembly (Microsoft.Rtc.Sdk.Categories.DLL—created in part 1 of this series), and the System.Xml.Serialization .NET Framework namespace to complete the following tasks:

  • Create an enhanced presence category instance as a CLR object.

  • Assign the category instance value by setting the properties on the CLR object.

  • Obtain the well-formed XML string of the category instance value by serializing the CLR object.

In part 3 of this series, you will learn how to use the enhanced presence schema object assembly to parse and display any category instances that you might receive in a presence subscription session.

Additional Resources

For more information, see the following resources:

About the Author

Kurt De Ding is a Senior Programming Writer in the Microsoft Office Content Publishing (UA) group.