Using Web Services Helpers to Access Data in Groove 2007

Summary: Reduce code complexity when accessing Microsoft Office Groove 2007 data by creating or using custom wrappers around the Microsoft Office Groove 2007 Web Services API. (13 printed pages)

Bob Novas, Microsoft Corporation

August 2007

Applies to: Microsoft Office Groove 2007, Microsoft Office Groove 2007 Server, Groove Web Services V12 Helpers, Microsoft Office Groove 2007 SDK

Contents:

  • Downloading the Software

  • Descriptions of the Software

  • Groove Web Services Helpers Overview

  • Groove Helpers Registry Usage

  • Building the Software from the Source

  • Groove Web Service Helpers Programming Examples

    • Spaces

    • Tools

    • Files Tool

    • Forms Tool

  • Tips and Considerations

  • SelectableObjectList and SelectableObject

  • Conclusion

  • Additional Resources

The Microsoft Office Groove 2007 Web Services API provides rich access to the Groove 2007 environment and to the data stored in Office Groove 2007 workspaces, but when you use this API directly, you must enter multiple lines of code to set up the Web services environment for each operation call. If you are creating a large, complex solution, you can reduce the size and complexity of your code by creating a set of wrappers that provide a higher level of abstraction.

The Groove Web Services V12 Helpers project provides such a set of wrappers. You can download this project from CodePlex, Microsoft's open source project hosting Web site. The Groove Web Services V12 Helpers is not a supported Microsoft product, but it provides an example of how wrappers can make the Groove 2007 Web Services API easier to use. You can download the Groove Web Services V12 Helpers binaries and use them directly; you can download the sources and modify them to fit your needs; or you can use Groove Web Services V12 Helpers as a model to develop your own set of wrappers. If you do add capabilities to the project or create your own set of wrappers, please consider sharing your code on CodePlex to help other Groove 2007 Web Services developers.

Microsoft Office Groove 2007 Web Services Helpers provide an API that is easier to use than the underlying Groove 2007 Web services; the API reduces the amount of code you need when you access Groove Web services directly. The Groove Helpers provide an object and an event model that allows you to write applications quickly and simply. You can also use the Groove Helpers to connect an application to Groove 2007 or to the Groove 2007 Data Bridge Server, making it easy to use a client for development and, after development, to move to an enterprise environment using the Groove 2007 Data Bridge Server.

The following code fragments compare the code you need to read the workspaces of an identity using the underlying Groove Web services APIs and using the Groove Web Services V12 Helpers API. The first code fragment uses the Groove Web services API directly:

// Create new service and header
GrooveSpaces.GrooveSpaces spacesSvc = new GrooveSpaces.GrooveSpaces();
spacesSvc.GrooveRequestHeaderValue = new GrooveSpaces.GrooveRequestHeader();

// Get the Identity2 from GrooveAccounts.Read2
GrooveAccounts.Identity2 ident = ... ;

spacesSvc.GrooveRequestHeaderValue.GrooveIdentityURL = ident.URI;

// Get the request key, HTTP address, and port number.
// See examples in Reading Groove Registry Keys
string requestKey = ... ; 
string HTTPAddressAndPort = ... ;

spacesSvc.GrooveRequestHeaderValue.GrooveRequestKey = requestKey;

// Get the GrooveSpaces PostURL from Identity2
spacesSvc.Url =  HTTPAddressAndPort + ident.Spaces;

GrooveSpaces.Space[] spaces = spacesSvc.Read("");

The second code fragment is much shorter and performs the same function by using the Groove Web Services Helpers API:

// get the identity
Identity m_Identity 
  = Account.GetAccounts(new Context())[0].Identities[0];

Space[] spaces = m_Identity.StandardSpaces;

To use Groove Web services (GWS) and the Groove Helpers, you should have the following:

  • Groove 2007 or Groove 2007 Server

  • Groove 2007 Software Development Kit

  • Microsoft Visual C# or Microsoft Visual Basic programming skills

  • Knowledge of the Microsoft .NET Framework, version 2.0

  • Microsoft Visual Studio 2005

Downloading the Software

You can download Groove 2007 software from the following locations.

Groove Client

To download a trial version of Groove 2007, see Try the 2007 Microsoft Office system.

Groove 2007 Software Development Kit (SDK)

The Groove Helpers use the Web Services Description Language (WSDL) of the Groove 2007 SDK but the SDK is not required to use the Groove Helpers. However, you should download the Groove 2007 Software Development Kit because the SDK includes important documentation. You can also see the latest Groove documentation at the Office Groove 2007 Developer Portal.

Groove Web Services Helpers

To download a copy of the Groove Helpers, see Groove Web Services V12 Helpers. Codeplex is Microsoft’s open source project hosting Web site. If you download the Groove Helpers using the link "current release,” you download the Groove Helpers Project Binaries. If you click the “More Releases” link instead, you have the choice of downloading the following:

  • Groove Helpers Project Binaries for provides the executables and libraries for the Command Line Utilities, the Groove Web Services Helpers, and the Groove Web Services Controls.

  • The Groove Helpers Source provides the source code for just the Groove Web Services Groove Helpers.

  • The Groove Helpers Project Sources provides the source code for the Groove Helpers, the controls and the command line utilities.

Figure 1 represents the Groove Helpers environment.

Figure 1. The Groove Web Services Helpers environment

Groove Web Services Helpers environment

Descriptions of the Software

Groove Web Services Helpers

The Groove Helpers .NET Framework assembly (GrooveWebServicesV12Helpers.dll) abstracts all the underlying Groove Web services and exposes a complete object and event model. This replaces code written to directly consume the GrooveEvents Web service.

Groove Web Services Command-Line Tools

The command-line tools allow you to test operations against a Groove Web services provider, such as the Groove 2007 client or Groove 2007 Data Bridge, without writing any code. The command-line tools implement most of the Groove Web services API and you can use the tools to write scripts that access Groove Web services.

Groove Web Services Controls

The .NET Framework application assembly (GrooveWebServicesV12Controls.dll) provides the following three UI controls:

  • TreeViewNavigator. Shows the user’s Groove workspaces and tools and allows the user to right-click to navigate to a specific space or tool or to see their properties.

  • ContactAwarenessViewer. Shows the user’s personal contacts, their awareness, and allows the user to right-click to send a contact a message, invite them to a workspace, or see their properties.

  • MemberAwarenessViewer. Shows the membership of a space.

  • You can use these controls in your own solutions, or you can examine them to see examples of code that uses the Groove Helpers.

Groove Web Services Helpers Overview

Groove 2007 and Groove Server 2007 Data Bridge both provide a server running Web services that is accessible with local Web services and, on some configurations, remote Web services. This article refers to Groove 2007 or Groove Data Bridge process generically as a Groove instance. The Groove Helpers require a connection to the Groove Web services (GWS) server running in a Groove instance. Furthermore, on a Groove instance that is a Groove client, except for a limited set of operations (Accounts.GetAccounts() and Account.Identities()), a user must be logged into an account in Groove for a Web services consumer to execute GWS operations.

It is helpful to capture the SOAP conversation between Groove and the Groove Web services consumer (See Tips and Considerations for details about debugging the SOAP conversation between an application and Groove).

Groove Helpers Registry Usage

The Groove Helpers use a registry key shown in Table 1. The Groove Helpers use the value in this key identified in Table 2.

Table 1. Groove Helpers Registry Key

Registry Key Description

Groove client

HKLM\Software\Microsoft\Office\12.0\Groove\WebServiceGroove Helpers

Table 2. Helpers Registry Value

Value Type Description

TraceEnabled

DWORD

A non-zero value enables the Groove Helpers to write trace information to diagnostic output (for example, dbgView or the debugger output window).

Building the Software from the Source

The software builds using Microsoft Visual Studio 2005. There are a number of solution (.sln) files that build the source. The All Build folder contains a solution file that builds all of the source.

Groove Web Service Helpers Programming Examples

Spaces

To create a Space using the Groove Helpers, use the Groove Helpers Identity methods CreateSpace, CreateSpaceFromGSA and CreateGrooveFileSharingSpace. The CreateSpace method creates an empty space to which you can add tools; the CreateSpaceFromGSA method creates a space from a Space archive or template; and the CreateGrooveFileSharingSpace method creates a Groove File Share (GFS) workspace and assigns a synchronization folder.

Example 1 shows sample code to list all spaces for an identity:

Example 1.List Spaces

    private void Form1_Load(object sender, EventArgs e)
    {
        try
        {
            // get the identity
            Identity m_Identity 
                = Account.GetAccounts(new Context())[0].Identities[0];

            Space[] spaces = m_Identity.StandardSpaces;
            SelectableObjectList SelectableSpaces 
                = new SelectableObjectList(spaces.Length);
            foreach (Space space in spaces)
            {
                SelectableSpaces.Add(new SelectableObject(space));
            }
            SelectableSpaces.Sort();

            …
        }
        catch (Exception ex)
        {
           TraceException(ex);
        }
    }

Tools

To add a tool to a workspace using the Groove Helpers, use the Groove Helpers Space.AddTool method. This method either takes a ToolTemplate, from the Space.ToolTemplates[] array, or a Component Resource URL. A ToolTemplate contains the Component Resource URL for tools provided with Groove. The ComponentResourceURL actually determines the tool (type and version) to add to a space.

The Space ToolTemplates[] array must be searched for a tool template by name. The tools available are:

Table 3. ToolTemplate IDs

Tool Template ID value Description

Discussion

Forms-based Discussion Tool

Issue Tracking

Forms-based Issue Tracking

Forms

Undesigned Forms Tool

InfoPath Forms

Undesigned Infopath Forms Tool

Meetings

Groove Meetings Tool

Calendar

Groove Calendar Tool

Files

Groove Files Tool

SharePoint Files

Unitialized Sharepoint Files Tool

Notepad

Groove Notepad Tool

Sketchpad

Groove Sketchpad Tool

Chess Game

Groove Chess Tool

Pictures

Groove Pictures Tool

Sample code to create all these tools, given an identity to use, is shown in Example 2.

Example 2. Create a Space and Tools and delete it

internal void Run()
    {
       try
       {
            string SpaceURI 
                = m_Identity.CreateSpace(
                "Create Stock Tools", 
                "See what the stock tools are", 
                "");
            Space space = m_Identity.OpenSpace(SpaceURI);

            foreach (ToolTemplate tt in space.ToolTemplates)
            {
                // add every tool in the ToolTemplates array
                space.AddTool(tt.LongName, tt);
            }
        }
        catch (Exception ex)
        
        {
            System.Diagnostics.Debug.WriteLine(
                String.Format("Exception - {0}", ex.Message));
            System.Diagnostics.Debug.WriteLine(String.Format("{0}", 
                ex.StackTrace));
        }
    }

The following example shows sample code to list all the Files Tools in a space. Note the use of the Shared namespace’s GROOVE_FILES_TOOL_SUPPORTED_TYPE. Such a constant exists in the Shared namespace for every type of tool and represents a good practice for determining the type of a tool.

Example 3. Listing Files Tools in a Space

    private void lbxSpaces_SelectedIndexChanged(
        object sender,
        EventArgs e)
    {
        try
        {
            GrooveWebServicesV12Helpers.Space space
                = (GrooveWebServicesV12Helpers.Space)
                ((SelectableObject)lbxSpaces.SelectedItem).Object;
            if (space == null) return;

            SelectableObjectList SelectableTools 
               = new SelectableObjectList(space.Tools.Length);

            Tool[] tools = space.Tools;
            foreach (GrooveWebServicesV12Helpers.Tool tool in tools)
            {
               if (tool.Type ==    
                   Shared.GROOVE_FILES_TOOL_SUPPORTED_TYPE)
                   SelectableTools.Add(new SelectableObject(tool));
            }
            SelectableTools.Sort();

            …
        }
        catch (Exception ex)
        {
            TraceException(ex);
        }
    }

Files Tool

The following example shows sample code to create a file in the root folder of a files tool. The code writes to the file from a byte array and then updates the file again from a byte array. There are also Files methods that create folders, and that create files by importing them from an existing file.

Example 4. Create and Update a File

    private void btnCreateFile_Click(object sender, EventArgs e)
    {
        Tool tool = 
           (Tool)((SelectableObject)lbxFilesTools.SelectedItem).Object;
        if (tool.GetType() == 
           typeof(GrooveWebServicesV12Helpers.Files.FilesTool))
        {
            GrooveWebServicesV12Helpers.Files.FilesTool filesTool 
                = (GrooveWebServicesV12Helpers.Files.FilesTool) tool;
            string fileURI = null;

            byte[] buffer = null;
            buffer = new byte[]{ 0, 1, 2, 3, 4, 5 };
            fileURI =  filesTool.RootFolder.AddFile("testing.txt", 
                "testing", buffer);
 
            GrooveWebServicesV12Helpers.Files.File file 
                = filesTool.RootFolder.OpenFile(fileURI);
            byte[] contents = file.Contents;
            int i=0;
            foreach (byte b in contents)
            {
                if (b != buffer[i])
                {
                    System.Diagnostics.Debug.WriteLine(
                        String.Format("mismatch at i={0}", i));
                }
                i++;
            }

            byte[] buffer2 = new byte[] { 6, 7, 8, 9, 10 };
            file.Update("testing.txt", "testing2", buffer2);

            byte[] updatedContents = file.Contents;
            i = 0;
            foreach (byte b in updatedContents)
            {
                if (b != buffer2[i])
                {
                    System.Diagnostics.Debug.WriteLine(
                        String.Format("mismatch at i={0}", i));
                }
                i++;
            }
        }
    }

Forms Tool

Working with data in a Forms tool is basically a matter of converting data back and forth between a System.Data.DataSet and a Groove RecordDataSet. The following example shows how to access data from a Forms Tool.

Example 5. Accessing Data from a Form in a Forms Tool

    try
    {
       DataSet ds = null;

       object aForm = …;

       if (aForm is GrooveWebServicesV12Helpers.Forms.Form)
       {
           GrooveWebServicesV12Helpers.Forms.Form form =
               (GrooveWebServicesV12Helpers.Forms.Form) aForm;
           GrooveWebServicesV12Helpers.Forms.FormsTool formsTool =
               form.FormsTool;
           GrooveWebServicesV12Helpers.Forms.RecordDataSet records 
               = formsTool.GetFormRecords(form.URI);
           if (records == null) return;

           ds = records.ToDataSet();
       }
       else if (aForm is GrooveWebServicesV12Helpers.Forms2.Form)
       {
           GrooveWebServicesV12Helpers.Forms2.Form form2 
               = (GrooveWebServicesV12Helpers.Forms2.Form) aForm;
           GrooveWebServicesV12Helpers.Forms2.FormsTool formsTool2 = 
               form2.FormsTool;
           GrooveWebServicesV12Helpers.Forms2.RecordDataSet records2 
               = formsTool2.GetFormRecords(form2.URI);
           if (records2 == null) return;

           ds = records2.ToDataSet();
       }
       …
   }
   catch (Exception ex)
   {
       TraceException(ex);
   }

Example 6 shows how to add new data to a Forms.FormsTool. The example also shows the right way to parse the FormID and the ParentID from the string given in the Form to the double required to write into the record. The format of a double written to a string is locale independent, and must be treated as such. The example also shows setting the _ParentID field if the record is a "response" record. In Forms2, the Form class indicates whether a form is used as a response record. This information is not available in Forms; consequently, your Helper application must be aware of how the forms are used in a specific Forms Tool Design.

Example 6. Writing .NET new data to a Forms.FormsTool

    private void WriteNetNewDataToForm(
        GrooveWebServicesV12Helpers.Forms.Form i_Form)
    {
        GrooveWebServicesV12Helpers.Forms.FormsTool formsTool = 
            i_Form.FormsTool;

        DataSet dataset = formsTool.Schema.ToDataSet();
        dataset.EnforceConstraints = false;
        DataTable table = dataset.Tables["FormsRecordData"];

        // get the form id as a double
        // Use InvariantInfo to parse the locale-independent double 
        // format correctly
        string sFormID = i_Form.ID;
        double dFormID 
            = System.Convert.ToDouble(sFormID,  
            System.Globalization.NumberFormatInfo.InvariantInfo);

        DataRow newRow = table.NewRow();

        // set the form ID in the row so the row actually belongs to 
        // this form
        newRow["Forms_Tool_grooveFormID"] = dFormID;

        // if it's a response record, set its parent RecordID
        if (tbxParentID.Text.Length > 0)
            newRow["_ParentID"] 
                = System.Convert.ToDouble(tbxParentID.Text, 
                System.Globalization.NumberFormatInfo.InvariantInfo);

        // add data to the row
        // newRow["...") = ...

        table.Rows.Add(newRow);
        dataset.AcceptChanges();

        GrooveWebServicesV12Helpers.Forms.RecordDataSet recordDataSet 
            = new GrooveWebServicesV12Helpers.Forms.RecordDataSet(
            dataset);
        string[] newURIs = formsTool.AddRecords(recordDataSet);

        foreach (string uri in newURIs)
        {
            // if adding multiple rows, uri's are in creation order
            System.Diagnostics.Debug.WriteLine(String.Format(
                "added URI={0}", uri));
        }
    } 

Example 7 The following code sample shows how to add new data to a Forms2.FormsTool. Note how to access the correct table in the data set. The example also shows setting the _ParentID field if the record is a "response" record. Unlike the Forms.FormsTool, there is an indication of this available in the form.

Example 7. Writing .NET new data to a Forms2.FormsTool

    private void WriteNetNewDataToForm(
        GrooveWebServicesV12Helpers.Forms2.Form i_Form)
    {
        GrooveWebServicesV12Helpers.Forms2.FormsTool formsTool = 
            i_Form.FormsTool;

        DataSet dataset = formsTool.Schema.ToDataSet();
        dataset.EnforceConstraints = false;
        DataTable table = dataset.Tables[i_Form.SchemaID];

        // get the form id as a double
        // Use InvariantInfo to parse the locale-independent double 
        // format correctly
        string sFormID = i_Form.ID;
        double dFormID = System.Convert.ToDouble(sFormID, 
           System.Globalization.NumberFormatInfo.InvariantInfo);

        DataRow newRow = table.NewRow();

        // set the form ID in the row so the row actually belongs to 
        // this form
        newRow["Forms_Tool_grooveFormID"] = dFormID;

        // if it's a response record, set its parent RecordID
        if (i_Form.IsResponse)
            newRow["_ParentID"] = 
                System.Convert.ToDouble(tbxParentID.Text, 
                System.Globalization.NumberFormatInfo.InvariantInfo);

        // add data to the row
        // newRow["...") = ...

        table.Rows.Add(newRow);
        dataset.AcceptChanges();

        GrooveWebServicesV12Helpers.Forms2.RecordDataSet recordDataSet 
            = new GrooveWebServicesV12Helpers.Forms2.RecordDataSet(
            dataset);
        string[] newURIs = formsTool.AddRecords(recordDataSet);

        foreach (string uri in newURIs)
        {
            // if adding multiple rows, uri's are in creation order
            System.Diagnostics.Debug.WriteLine(
                String.Format("added URI={0}", uri));
        }
    }

Example 8 shows how to access file attachments, which are slightly different in Forms and Forms2. Attachments are accessed by invoking GetFormFileAttachments() on a data row read from a data set created from a Forms or Forms2 record data set that includes attachments. The code that reads the record data set from the Forms tool must specify that attchments are included; the code is shown below:

    bool IncludeFileAttachmentContent = true;
    GrooveWebServicesV12Helpers.Forms2.RecordDataSet records2 
        = formsTool2.GetFormRecords(form2.URI, 
        IncludeFileAttachmentContent);
    if (records2 != null && records2.Data.Length > 0)
        ds = records2.ToDataSet();

The members of the Forms and Forms2.FormFileAttachment class are slightly different.

Example 8. Forms and Forms2.FormFileAttachment

    private void ShowAttachments(DataRow row)
    {
        GrooveWebServicesV12Helpers.Forms.FormFileAttachment[] 
            attachments = GrooveWebServicesV12Helpers.Forms.FormFileAttachment.GetFormFileAttachments(row);

        SelectableObjectList SelectableAttachments 
            = new SelectableObjectList(attachments.Length);
        foreach (
            GrooveWebServicesV12Helpers.Forms.FormFileAttachment
           attachment 
           in attachments)
        {
            SelectableAttachments.Add(new SelectableObject(
                attachment.DisplayName, attachment));
        }
        SelectableAttachments.Sort();

        …
    }

    private void ShowAttachments2(DataRow row)
    {
        GrooveWebServicesV12Helpers.Forms2.FormFileAttachment[] 
            attachments = GrooveWebServicesV12Helpers.Forms2.FormFileAttachment.GetFormFileAttachments(row);

        SelectableObjectList SelectableAttachments 
           = new SelectableObjectList(attachments.Length);
        foreach (GrooveWebServicesV12Helpers.Forms2.FormFileAttachment 
            attachment 
            in attachments)
        {
            SelectableAttachments.Add(new SelectableObject(
                attachment.FullName, attachment));
        }
        SelectableAttachments.Sort();

        …
    }
}

When you write data to a Forms tool, you are associating the data with a FormID given by a floating point number. This number must exactly match the ID of a form in the tool for the record to actually be associated with that form. If the number does not match the ID of a form in the tool, there is no error—the record is written to the Forms tool, but is not associated with any Form.

If there is a view in the form that does not filter the view by Form, the record shows up in that view. But, if you try to read the record from the Form, the record does not appear to exist because it is not associated with the form. This can be difficult to diagnose.

Another issue that can arise is if you create a record URI by formatting the RecordID from a double to a string. To create all record IDs properly, be sure to use the "R" format specifier (the "round-trip" specifier) to get full precision in the resulting string form of the double.

Tips and Considerations

Cached Objects

The Groove Helpers cache objects and if you modify or delete a cached object, the Groove Helpers do not automatically update their cache. So, for example, because the Identity object caches workspaces, if you (or someone else) renames a workspace, the cached Space object does not reflect the change. You have to refresh the cache, which, generally, is not an issue.

Performance

In general, creating and opening workspaces are time-consuming and resource-intensive operations. Reading many records from a Forms tool is also expensive. To get information about the performance of a specific Web service operation, you can enable tracing. Tracing Web service operations prints out the time spent executing Web services in the application’s execution path.

An event conveys substantial data about the specifics of the event. It is much more efficient to process the information conveyed by the event than to react to an event by using another Groove Web service operation to fetch the same information again from Groove.

Surviving Groove Shutdown and Startup

Because the lifetime of an application that consumes Groove Web services is independent of the lifetime of a Groove instance, an application that consumes Groove Web services should pay attention to what happens when the Groove instance shuts down and restarts.

This becomes important because Groove changes the value of the LocalRequestKey and LocalResponseKey in the registry when it starts. The Groove Helpers throw the following System.NET.WebException the next time they execute a Groove Web services operation; Unable to connect to the remote server, with an inner exception of System.NET.Sockets.SocketException, error code 0x274D, ConnectionRefused.

This is difficult to handle. Either the Groove Web services consumer should shut down and restart when Groove is started again, or the consumer should make some attempt to wait for Groove to restart and then establish a new context, which gets the new values for LocalRequestKey and LocalResponseKey.

Debugging using the SOAP conversation between the Application and Groove

To view the SOAP conversation between the Groove Web services consumer and Groove. You can use a utility like tcptrace (http://www.pocketsoap.com/tcpTrace/) or Fiddler (http://www.fiddlertool.com/fiddler/) to see the SOAP conversation.

Here is one way to set up the Groove instance and application to allow the utility to capture the SOAP conversation. The Groove Helpers honor HKLM\$PRODUCT$\GrooveHTTPDesiredPort (unless remote access is enabled by specifying a RemoteRequestKey). First, change GrooveHTTPDesiredPort to port 8080. Then restart Groove so that it comes up on port 8080. Next, change GrooveHTTPDesiredPort back to 9080. Now run the trace utility to pipe 9080 to 8080 and run your application. The Groove Helpers honor the GrooveHTTPDesiredPort setting of 9080, which the utility maps to 8080, and the LocalRequestKey works correctly. If you restart Groove, you must go through this setup again.

Check the Registry

If you have problems running the Groove Helpers against a Groove instance, check the registry. Figure 3 illustrates a problem. Groove is running against port 9081, but the Groove Helpers, which run against GrooveHTTPDesiredPort, try to connect to 9080. In this situation, restart Groove and check that the GrooveHTTPPort is the same as the GrooveHTTPDesiredPort.

Figure 3. Trouble in the Registry

Trouble in the Registry

Reading CodePlex and Posting Issues to CodePlex

Remember to look at CodePlex to see if there are any issues reported against problems you might have. Also, if you do run into a problem, be sure to post it to CodePlex so that someone can take a look at it.

SelectableObjectList and SelectableObject

The following examples show the SelectableObjectList and the SelectableObject classes used by many examples in this document.

Example 9. SelectableObjectList Class

    public class SelectableObjectList : ArrayList
    {
        public SelectableObjectList(int i_Capacity)
            : base(i_Capacity)
        {
        }

        public SelectableObjectList(IList i_WSObjects)
        {
            foreach (object o in i_WSObjects)
                base.Add(new SelectableObject(o));

            base.Sort();
        }

        public SelectableObjectList(IList i_WSObjects, 
            string i_SelectionLabel)
        {
            foreach (object o in i_WSObjects)
                base.Add(new SelectableObject(o));

            base.Sort();
            base.Insert(0, new SelectableObject(i_SelectionLabel,
                null));
        }

        public SelectableObjectList(string[] i_StringList, 
            string i_SelectionLabel)
        {
            foreach (string s in i_StringList)
                base.Add(new SelectableObject(s, s));

            base.Sort();
            base.Insert(0, new SelectableObject(i_SelectionLabel, 
                null));
        }
    }

Example 10. SelectableObject Class

    public class SelectableObject : IComparable
    {
        private object m_Object;
        private string m_Name;
        private string m_URI;

        public SelectableObject(object i_WSObject)
        {
            m_Object = i_WSObject;

            if (i_WSObject is GrooveWebServicesV12HelpersBase)
            {
                m_Name = 
                    ((GrooveWebServicesV12HelpersBase)i_WSObject).Name;
                m_URI = 
                     ((GrooveWebServicesV12HelpersBase)i_WSObject).URI;
            }
        }

        public SelectableObject(string i_String, object i_Object)
        {
            m_Name = i_String;
            m_Object = i_Object;
            m_URI = null;
        }

        public string Name
        {
            get { return m_Name; }
        }

        public string URI
        {
            get { return m_URI; }
        }

        public object Object
        {
            get { return m_Object; }
        }

        #region IComparable Members

        public int CompareTo(object obj)
        {
            return m_Name.CompareTo(((SelectableObject)obj).m_Name);
        }

        #endregion
    }

Conclusion

You can reduce the amount of time it takes to develop a Groove Web services application by using a set of wrappers. The Groove Web Services V12 Helpers project provides such a set of wrappers that reduce the number of lines of code needed to call the Groove Web services operations.

Additional Resources

For more information, see the following resources:

Using Web Services Helpers to Access Events in Groove 2007

CodePlex, Microsoft's open source project hosting Web site