In Part 1 of this series, we covered how to create a new Word 2007 ribbon that shows and hides the Actions Pane. Today we’re going to see how course information can be retrieved from SharePoint using a built in web service, so that the information can be dynamically placed into the Word document itself.

The information we’re going to be retrieving is information relating to a particular college course. The information is stored in a SharePoint Forms Library. (The idea is that professors have submitted course information for the upcoming semester using an InfoPath form.) The InfoPath Form associated with the Library has been published in such a way that the information from the form is extracted and put into three columns: CourseTitle, CourseNumber, and CourseDescription.

Courses Form Library

Although the information from the Form Library will be returned as XML, it will be easier to work with if we create an object representing a course. Create a new C# class and add the following code to it:

using System;
namespace MySampleWordDocument
{
   class Course
   {
       private string title;
       private string courseNumber;
       private string description;
       private string professor;
       public string Title
       {
           get { return title; }
           set { title = value; }
       }

       public string CourseNumber
       {
           get { return courseNumber; }
           set { courseNumber = value; }
       }
       
       public string Description
       {
           get { return description; }
           set { description = value; }
       }
   }
}

As you can see, our Course C# class has three public properties: the name of the course, the course number, and the course description.

When writing a SharePoint Feature, it’s possible to use the SharePoint API because the SharePoint DLL’s you’re referencing are installed right there on the web server. However, since this code is going to be called from a user’s desktop, it’s necessary to use a web service to retrieve information from the SharePoint list where the course data is stored. In our scenario, professors submit InfoPath forms to a Form Library with information regarding the courses they’ll be offering that semester.Our web service will be retrieving all the InfoPath Form List Items from the Form Library, providing the author of the Word document with a list of available courses that can be added to the Word document.

The first thing we need to do is to add a reference to the web service we’ll be using. To do this, right click on your project in Visual Studio, and select “Add Service Reference” from the menu.
Add Service Reference

In the dialog box that appears, click on the “Advanced” button in the bottom left corner.
Add Service Reference Advanced

On the dialog that appears, click on the “Add Web Reference” button at the bottom of the page.
Add Web Reference

Each IIS Web Application that’s associated with a SharePoint site should have a Virtual Directory called “_vti_bin”. This directory holds the SharePoint .asmx web service files you can reference. For our example, we’ll be using the “StsAdpater” web service, which has a file name of “DspSts.asmx”. As you can see in the example below, my SharePoint site’s URL is sandbox.moss.com, so my web reference points to “http://sandbmox.moss.com/_vti_bin/DspSts.asmx”. We’ll name the web reference ListdataRetrievalWebService. Click the “Add Reference” button after you’ve renamed the Web reference name.
Web Service

Now that you have created a Web Reference, it’s time to create a collection object that will use the web service to retrieve courses and place them in the collection. Create a new C# class file called “Courses.cs”. We’ll need three “using” statements at the top of the class:

using System.Collections.Generic;
using System.Xml;
using WS = LOBDoc.ListDataRetrievalWebService;

Our collection class is going to inherit from the Generic namespace’s List object, which is why we need the first “using” statement. We’ll referencing our web service, and we’ll be iterating through the XML string the web service will give us, which is why we need the last two “using” statements.

Next, create your class declaration:

namespace LOBDoc
{
   class Courses : List<Course>
   {
   }
}

Now that you have your “Courses” Generic List object, we’re going to create a constructor that will automatically retrieve all the course information from the Courses Form Library on the SharePoint Server, and populate your new “Courses” List with a bunch of new “Course” objects.

The first thing you’re going to do is instantiate a new StsAdapter object from your Web Service.

WS.StsAdapter stsa = new WS.StsAdapter();

You’ll need to pass it a set of credentials. For this example, we’ll pass in the credentials the Word application is running under.

stsa.Credentials = System.Net.CredentialCache.DefaultCredentials;

The next thing you need to do is, in a very verbose fashion, tell the web service that you’re using version 1.0 of the data retrieval service.

string[] versionsArray = new string[1];
versionsArray[0] = "1.0";
WS.Versions versions = new WS.Versions();
versions.version = versionsArray;
stsa.versions = versions;

Now, the next part can seem a bit tricky because of all the properties with the word “Query” in them. To break it down:

  • A QueryRequest object has a property of type DSQuery.
  • A DSQuery object has a property of type DspQuery.

The end goal in our example is to pass in the GUID of the Form Library we’re querying. (If we wanted to pass in more specific query parameters, we would do it here.)

WS.DSQuery dsq = new WS.DSQuery();
dsq.select = "/list[@id='{ABBD2A31-AE35-40EC-AE7A-658758E767A7}']";
WS.DspQuery dspq = new WS.DspQuery();
dsq.Query = dspq;
WS.QueryRequest qr = new WS.QueryRequest
qr.dsQuery = dsq;

Finally, we’re going to create a Request Header that we will send with the Web Service request. The header passes in rather obvious information, such as the fact that we are querying content.

WS.RequestHeader rh = new WS.RequestHeader();
rh.document = WS.DocumentType.content;
rh.method = WS.MethodType.query;
stsa.request = rh; 

We’ve now constructed an Adapter object. The last thing to do is to call the Web Method that will execute your query and send you back an XML result set. We’re selecting the node called “Courses” because the information from the “Courses” Forms Library is what we want to iterate through.

XmlNode listItemsNode = stsa.Query(qr);
XmlNode coursesNode = listItemsNode.SelectSingleNode("Courses");

Now that we have our resulting XML, we’ll iterate through the XML, creating a Course object for each XML node, and then adding the Course object to the Courses collection.

foreach (XmlNode courseNode in coursesNode.ChildNodes)
{
     if (courseNode.GetType().ToString() != "System.Xml.XmlWhitespace")
     {
         Course course = new Course();
         course.Title = courseNode.SelectSingleNode("CourseTitle").InnerText;
         course.CourseNumber = courseNode.SelectSingleNode("CourseNumber").InnerText;
         course.Description = courseNode.SelectSingleNode("CourseDescription").InnerText
         this.Add(course);
     }
}

Now that we have the code rewritten to retrieve information from SharePoint using a Web Service, let’s test it out in our Word document. Remember the Actions Panel we worked on in Part 1? Let’s add a control to it that will display all the available courses.

Double click on ActionsPaneControl1.cs in your project to open up the Actions Pane Control in Designer view. Drag and drop a control of type ListBox onto the Actions Pane Control surface. We’ll give the control a name of “courseSelectorListBox”. Now right click on ActionsPaneControl1.cs in the project tree view and select “View Code” from the context menu. Add the following method to the class

private void ActionsPaneControl1_Load(object sender, EventArgs e)
{
}

Then add an Event Handler referencing that method to the class constructor. It should now look like this:

public ActionsPaneControl1()
{
     InitializeComponent();
     this.Load += new EventHandler(ActionsPaneControl1_Load);
}

We just created a method that will be called when the Actions Pane Control is loaded. Our method will bind our ListBox control to our Courses List object. Add the following code to the ActionsPaneControl1_Load method:

Courses courses = new Courses();
courseSelectorListBox.DataSource = courses;
courseSelectorListBox.ValueMember = "Title";
courseSelectorListBox.SelectedIndex = -1; 

Remember that we are calling the Web Service from the Courses constructor, so by virtue of instantiating a new Courses object, we’re populating it with new Course objects. We’re binding the ListBox control’s “DisplayMember” and “ValueMember” properties to the Course object’s “Title” property. Last but not least, we’re setting the ListBox’s “SelectedIndex” property to -1 to ensure no Courses are selected by default.

Now, try running your project in Debug mode. When you click on the “Add Course(s)” button on the ribbon, the Actions Pane should appear, and you should see the list of courses from the Courses Forms Library in SharePoint.

List Box