IN THIS CHAPTER
Of all of the various things developers do with Microsoft Office SharePoint Server (MOSS), one of the most common programming tasks is exposing SharePoint list data to external applications via web services. This chapter provides a look at the various list-related web services that make this possible. In addition, this chapter covers working with views and even provides some insight into creating a class library that makes programming with SharePoint lists easier and simpler.
You can access SharePoint list data programmatically via web services in two main ways. The following briefly describes each of these web services and what functionality they provide. The rest of the chapter provides you with an in-depth look at how to program against each of these web services.
Lists.asmx
—This web service provides methods for retrieving and updating details about the list itself, such as the list title. In addition, you can also use this web service to retrieve and update list items and even retrieve filtered list items based on Collaborative Application Markup Language (CAML) queries.Views.asmx
—Views are a large part of working with SharePoint lists and this web service provides excellent programmability support for views. You can use this web service to create new views, delete views, update views, obtain the list of views available to a list, and so forth.When working with relational data sources such as SQL Server or Oracle, developers often refer to an acronym called CRUD. This acronym refers to the minimum required operations that should be supported for any entity: Create, Retrieve, Update, and Delete. This section illustrates the various forms of creation, retrieval, deletion, and updating that are available with the Lists Web Service.
Retrieving lists and list items is done through a few straightforward methods such as GetList
and GetListItems
. The columns contained in Table 22.1 are the columns that will be contained in the Extensible Markup Language (XML) resultset from calling GetList
as attributes. For a list of the attributes of a list that can be modified, see Table 22.2 in the next section.
Table 22.2. Updatable List Properties
To see the Lists.asmx
Web Service in action to retrieve lists and list items, create a new Windows application and add a web reference to the Lists.asmx
Web Service. You can find this service in the _vti_bin
directory beneath any SharePoint site. The Lists Web Service for the root site of a portal can be found at http://[portal-server]/_vti_bin/Lists.asmx and you might find the Lists Web Service for an HR team site at http://[portal-server]/sitedirectory/HR/_vti_bin/Lists.asmx.
After creating the Windows application, add a TextBox
called siteUrl
, a button called retrieveListsButton
, a ListView
called siteLists
and, finally, a ListBox
called titleLists
. Create event handlers for the button’s Click
event and for siteLists
’ SelectedIndexChanged
event. The code for this application is shown in Listing 22.1. The application retrieves all of the lists at a given site using the GetListCollection
method, and then attempts to retrieve the title of each list item using the GetListItems
method.
Listing 22.1. The ListRetriever
Application
The first thing that you will notice about programming with the Lists Web Service is that everything is XML-based. The results of the call to GetListCollection
return a set of XML and attributes described in Table 22.1. The call to GetListItems
returns XML in a format that is roughly equivalent to the old ADO RecordSet
format. Although the XML can be read by an ADO.NET DataSet
Class, many simple list item tasks don’t require the overhead of a full DataSet
.
The other thing you might notice is that the XML returned by GetListItems
uses a peculiar “ows_” prefix on all attribute names. This is a throwback from the days before SharePoint 2001 when the product was referred to as the “Office Web Server.” Every list item in SharePoint has an ows_ID
attribute, and most of them have an ows_Title
attribute indicating a short description for the item.
Each SharePoint list has its own schema, and you might find that even though the lists might appear similar in the SharePoint graphical user interface (GUI), their schemas can differ greatly. As you encounter lists against which you want to program, you should print out a schema cheat sheet showing the column name in the GUI, the attribute name in XML, and the data type. Wherever prudent, this book provides you with those schemas but you should make a habit of keeping them nearby as you develop against the Lists Web Service.
Through the UpdateList
method, you can update list details such as various configuration settings and the list’s title and description. In addition, you also have the ability to create new fields, update existing fields, and delete existing fields within the list. This same functionality is available through the SharePoint front end by clicking Settings and then List Settings when viewing the list.
The UpdateList
method takes the following parameters:
listName
—The name/GUID of the list to be updated.listProperties
—An XML node containing all of the list properties to be modified.newFields
—An XML node containing all of the fields that are to be added during the transaction. This XML contains a list of “method” nodes to provide individual item auditing.updateFields
—An XML node containing all of the existing fields that are to be modified during the transaction.deleteFields
—An XML node containing the fields to be deleted.listVersion
—A String indicating the list version.The data contained in each of the XML nodes is specific to the list being modified. Essentially, this means that your code should be aware of the list schema before adding, deleting, or updating fields. Table 22.2 shows all of the list properties that can be modified by UpdateList
.
The UpdateList
method is extremely powerful and can be extremely handy. However, it can often be difficult or impossible to recover from list schema changes made programmatically. Because of this, it is always a good idea to test your code on duplicate lists with production schemas instead of on lists being used in production.
The following code modifies the properties of an existing list as well as creates two new columns: First Name and Last Name:
All of the XML fragments for updating and creating fields follow the same format:
<Fields>
<Method Cmd="#">
<Field>
< ... >
<Formula>..</Formula>
</Field>
</Method>
</Fields>
The following code makes use of the optional <Formula>
subelement and adds a new calculated field that concatenates the first and last names using the common “last, first” format (note that this call doesn’t work unless you’ve already created the First Name
and Last Name
columns):
When updating a list, you need to know the GUID of the list to modify it, and you know which columns can be updated at development time because the list schema is a fixed schema. List items, however, can have varying schemas. The data contained in a Task
list is going to vary greatly from the data contained in a DefectTracking
list or a Contacts
list. As such, the code to update list items is specific to the type of items being updated. For each collection of list items to be updated, you will send an XML <Batch>
element containing the change list. The following code illustrates changing the title of two different list items contained within the same list as well as adding a new item and deleting yet another item. Note that not only is the list GUID required, but the ID of each item is also required to perform the update. The <Batch>
element represents a collection of New, Update, and Delete commands corresponding to individual list items.
Listing 22.2 is from a console application that creates a new list item, updates an existing item, and deletes an existing item. The schema is based on the one created in the previous section (a custom list with a First Name and Last Name field as well as a calculated Full Name field).
Listing 22.2. Console Application to Create a New List Item, Update Form, and Delete Existing Item
One of the most useful tools when updating list items is the XmlNode
that you get back from the UpdateListItems
call. If there is an error, it contains a (usually) precise description of what went wrong. If everything was successful, the node actually contains a copy of each modified row. If you inserted a new item, the copy of that item in the resulting XML contains the automatically assigned ID
column.
You might notice that the name of the First Name field, when passed to UpdateListItems
is First_x0020_Name
. The x0020
is an XML representation of the space that occurs in the field name.
It is often frustrating to the point of madness to deal with the inconsistencies in representations of data with SharePoint lists. You might have noticed that the data you receive from SharePoint looks nothing like the data you send to SharePoint using the Lists Web Service. When working with any SharePoint list, you might want to keep a copy of the output XML (the row/column metaphor) and a copy of a decent input XML (the batch metaphor) handy for reference to keep the confusion as small as possible. Sadly, this is one of the pain points for programmers that did not get fixed in the 2007 version.
In previous versions of SharePoint, the model for dealing with hierarchical data was either extremely immature or simply didn’t exist. You had the ability to have one column’s value be chosen from a list of items contained in another list, which was well suited to the task of selecting a defect status stored in a Defect Statuses list. However, trying to force that model to support the notion of things like Orders and Order Items or Customers and Customer Phone Numbers didn’t work well at all.
Using a new concept in MOSS 2007 called content types, you can create arbitrarily deep hierarchies for storing data in SharePoint lists. For example, you could create a content type called Order
that inherits from the Folder
type. This would allow orders to contain items, possibly even items of the content type Order Item
. This use of content types allows a parent folder to have separate metadata from the items contained within it: the ideal scenario for modeling parent/child data in a single SharePoint list. Coupled with the notion that SharePoint list item storage is more efficient than in previous versions and is now highly indexed, this provides a viable alternative for storing data in a relational database if storage within SharePoint is more convenient. Obviously, large database scenarios aren’t appropriate for SharePoint, but the ability to store hierarchical data presents new options to developers that might not have been available in SharePoint 2003.
To see how this all works, start with a new team site. On that team site, add a new content type called Order
and add a column called Order Number
to that content type. Next, add a site content type called Order Item
and add the following columns to it: SKU
and Item Number
. Now go and create a list and associate the Order
and Order Item
content types with that list. If everything has worked, you should see two new drop-down menu items under the New
button on the list’s default view: New Order
and New Order Item
.
Before taking a look at the code, you should notice one important thing about how the Lists Web Service provides list items that are associated with a content type. By default, if you request a list of items, you do not get all of the columns like you would if you were dealing with standard list items. Instead, you must use the ViewFields
XML element to manually specify the fields you want to retrieve. When you consider that content types allow individual items contained within a list to have completely different schemas, requiring the developer to manually request fields makes a lot of sense. The code in Listing 22.3 shows a complete console application that requests orders (parent folders) and then subsequently requests all items contained within each order. To request list items contained within a folder, you must specify the <Folder>
option in the <QueryOptions>
XML parameter to GetListItems
.
Listing 22.3. Querying Hierarchical List Item Data Using Content Types
The preceding code produces output that looks like the following (assuming you have created some sample Order folders and Order Items contained within them):
Order: First Order
Order #: 1001.00000000000
Item 1.00000000000000: MP3 Player
SKU: MP3100
As you can see, the folder/item paradigm is extremely powerful when coupled with the parent/child pattern for storing and retrieving hierarchical data and could potentially be one of the most powerful new features in Microsoft Office SharePoint 2007 beside the Business Data Catalog for using SharePoint as a data back end.
In previous versions of SharePoint, the ability to track changes to a list item was limited only to document library lists. With MOSS, you can now track revisions to any list item in any list. In addition, instead of simple numerical revision numbers, MOSS 2007 supports major and minor version numbers. This section shows you how the Lists Web Service has been updated to include support for revision control.
One of the revision control methods, GetVersionCollection
, retrieves a list of changes to a specific field within a list item in a given list. The method call:
XmlNode versions =
listService.GetVersionCollection("Updated List Title", "4", "Title");
yields the following XML:
Note that because you are looking purely at the change in one field over time, there is no revision number included, as the revision number applies to the entire list item and not just one field.
If you use the GetListItemChanges
method on the Lists Web Service, you can get a list of changes made to list items since a given date. This provides you a field called ows_owshiddenversion
that shows the item version.
Although the version control story for the Lists Web Service is certainly not as fleshed out as it could be, it’s a useful start. As always, if you find functionality that is provided in the application programming interface (API) but is not exposed well or at all through a web service, you can write your own web service that is tailored specifically to your needs. In this case, you might consider writing a web service that provides a more robust version control querying system.
So far, you have seen how to get list data and list items based on unique identification strings. This section shows you how you can use a CAML query to filter the results of a GetListItems
operation.
You have to be extremely careful when adding web references to your Visual Studio 2005 projects. You cannot rely on the web reference system to give you the URL you want. For example, an attempt to reference http://lab/sitedirectory/research/_vti_bin/lists.asmx often results in a reference to http://lab/_vti_bin/lists.asmx. This is obviously not the site you were attempting to reference. This is why the service URL is manually set at runtime in all of the samples throughout this chapter.
You can do more than just filter using CAML queries—you can sort as well. For a full list of what’s available through CAML queries and a reference on the syntax for building such queries, consult the SharePoint Software Development Kit (SDK) documentation. The following few lines of code illustrate both sorting and filtering:
The output from the preceding code looks like this (alphabetically sorted by item title, showing only those items whose first name is “Bob”):
This is a new item : string;#Jones, Bob
Title Changed Again Again Again : string;#Jones, Bob
Note that the format of the calculated string isn’t just simple output: It uses a special syntax where the data type of the calculated field is displayed, then the “;#” delimiter, followed, finally, by the actual field data.
Views are an incredibly powerful complement to lists within SharePoint. Views allow administrators to display, sort, and filter data in multiple different ways, and personal views can even allow individual users to create their own views on public data. This section of the chapter shows you how you can manipulate and query views using the Views Web Service.
To create a view, you need to know the name of the list that will act as the source for the view, as well as the fields you want displayed in the view, and the query you want to produce the view’s output. The following code produces a new view containing only items that have a First Name
column containing the value Bob
. This view only shows the Last Name
and Title
columns.
Deleting a view is pretty simple. All you need is the name of the list and the name of the view, as follows:
viewService.DeleteView("Updated List Title", "Bob Items");
To obtain the list of views available for a given list, simply issue the following method call:
XmlNode viewCollection = viewService.GetViewCollection("List Name");
This returns an XML node called Views
that contains a list of views. The following lists some of the important attributes on each child View
node:
Name
—The name of the view (GUID)DisplayName
—The friendly name of the viewDefaultView
—A Boolean indicating whether the view is the current default for the listUrl
—A direct link to the view (does not include server name)ImageUrl
—An icon for the viewThe Lists Web Service is one of the most frequently used web services within SharePoint. This chapter has provided you with an in-depth look at some of the tremendous power available at the fingertips of developers using the Lists Web Service and the Views Web Service. Using code samples in this chapter, you can create lists, update list items, query lists and list items, create views, and much more.