February 24, 2021
Hot Topics:

SharePoint and Web Services

  • By Mike Gunderloy
  • Send Email »
  • More Articles »

In my last article, I showed you how to work with Windows SharePoint Services from within Microsoft Office 2003. But what if you're using something other than Office 2003 as as development environment, and want to tap into SharePoint data? No problem! In this article, I'll give you a quick overview of the Web services interface to SharePoint.

The SharePoint Web Services

Windows SharePoint Services was being designed and developed during the time when Microsoft was beginning to heavily push Web services. It should be no surprise, then, to find out that you can get at the data in SharePoint through Web services. In fact, there's not just one Web service involved; there are 16. Here's a brief rundown of the Web services that a SharePoint server makes available out of the box:

  • http://server:5966/_vti_adm/Admin.asmx - Administrative methods such as creating and deleting sites
  • http://server/_vti_bin/Alerts.asmx - Methods for working with alerts
  • http://server/_vti_bin/DspSts.asmx - Methods for retrieving schemas and data
  • http://server/_vti_bin/DWS.asmx - Methods for working with Document Workspaces
  • http://server/_vti_bin/Forms.asmx - Methods for working with user interface forms
  • http://server/_vti_bin/Imaging.asmx - Methods for working with picture libraries
  • http://server/_vti_bin/Lists.asmx - Methods for working with lists
  • http://server/_vti_bin/Meetings.asmx - Methods for working with Meeting Workspaces
  • http://server/_vti_bin/Permissions.asmx - Methods for working with SharePoint Services security
  • http://server/_vti_bin/SiteData.asmx - Methods used by Windows SharePoint Portal Server
  • http://server/_vti_bin/Sites.asmx - Contains a single method to retrieve site templates
  • http://server/_vti_bin/UserGroup.asmx - Methods for working with users and groups
  • http://server/_vti_bin/versions.asmx - Methods for working with file versions
  • http://server/_vti_bin/Views.asmx - Methods for working with views of lists
  • http://server/_vti_bin/WebPartPages.asmx - Methods for working with Web Parts
  • http://server/_vti_bin/Webs.asmx - Methods for working with sites and subsites

To use any of these Web services, replace server with the name of your SharePoint server. Because they're implemented using ASP.NET code, you can retrieve the matching WSDL file for any service by appending ?WSDL to the end of the URL. When you do so, you'll discover that each one supports multiple methods, making this one of the richest sets of Web services of any current product. For full information on the available Web methods, download the SharePoint Products and Technologies 2003 SDK.

VB.NET to SharePoint

To see how this works in practice, I'll build a simple client using Visual Basic .NET 2003. To hook the client application up to my SharePoint server, I selected Add Web Reference from the References node shortcut menu in Solution Explorer. Entering the URL for one of the SharePoint Web services shows me all of the methods supported by that service, as shown in Figure 1.

Setting a reference to a SharePoint Web service

Adding the reference makes all the methods of the Web service available to the Visual Basic .NET client application. Well, almost. SharePoint servers require authentication, and the proxy class that Visual Studio .NET creates automatically doesn't pass any credentials to the Web service. Fortunately, that's easy to fix by adding one line of code. Click the Show All Files button on the Solution Explorer toolbar and drill into the Web reference you just added until you find the Reference.vb file; this is the proxy class. Open this file and add a line to the constructor to pass the user's default credentials:

Public Sub New()
    Me.Url = "http://seesaw/_vti_bin/Lists.asmx"
    Me.Credentials = System.Net.CredentialCache.DefaultCredentials
End Sub

Of course, the URL for your own SharePoint server will be different than mine. Now, I'm going to use the SharePoint Web service to do two things. First, I'll retrieve information about all of the lists on the server to a DataGrid control. Second, when the user clicks on a row in the DataGrid, I'll display the information from the corresponding list in a TextBox control. So, I've added a DataGrid named dgLists and a TextBox named txtData to the default form in my VB .NET application. When the form loads, this code will fill the DataGrid with information on the lists:

Private Sub Form1_Load(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) Handles MyBase.Load
    ' Get the list of lists from the server
    Dim L As New WSS_Server.Lists
    ' The list is returned as an XmlNode object
    Dim n As XmlNode = L.GetListCollection
    ' Prepare objects to handle the data
    Dim xd As XmlDataDocument = New XmlDataDocument
    Dim ds As DataSet = xd.DataSet
    ' Add an XML declaration to make the 
    ' XmlNode a valid XML document
    xd.LoadXml("<?xml version='1.0' ?>" & n.OuterXml)
    ' Display the result on the DataGrid
    dgLists.DataSource = ds
    dgLists.DataMember = "List"
End Sub

Most of the methods from the SharePoint Web services return XmlNode objects. An XmlNode object represents a node in an XML file, plus all of its children, but it isn't a full XML document. You can use various methods to parse information from an XmlNode, but I'm going to turn it into a DataSet. The key to this is the XmlDataDocument object. The XmlDataDocument can hold any XML document, but it also exposes the document, via its DataSet property, as a DataSet. This gives me an easy way to map XML data to a DataGrid.

Before you load data from an XmlDataDocument into a DataSet, you need to specify the schema of the DataSet. This is especially useful if you want to display only some elements from the XML data. In this example, I've created a schema file that exposes all of the information in the XML as simple string columns:

<?xml version="1.0" standalone="yes"?>
<xs:schema id="Lists"
 attributeFormDefault="qualified" elementFormDefault="qualified">
  <xs:element name="Lists" msdata:IsDataSet="true"
      <xs:choice maxOccurs="unbounded">
        <xs:element name="List">
            <xs:attribute name="DocTemplateUrl" form="unqualified"
             type="xs:string" />
            <xs:attribute name="DefaultViewUrl" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ID" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Title" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Description" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ImageUrl" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Name" form="unqualified"
             type="xs:string" />
            <xs:attribute name="BaseType" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ServerTemplate" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Created" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Modified" form="unqualified"
             type="xs:string" />
            <xs:attribute name="LastDeleted" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Version" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Direction" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ThumbnailSize" form="unqualified"
             type="xs:string" />
            <xs:attribute name="WebImageWidth" form="unqualified"
             type="xs:string" />
            <xs:attribute name="WebImageHeight" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Flags" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ItemCount" form="unqualified"
             type="xs:string" />
            <xs:attribute name="AnonymousPermMask" form="unqualified"
             type="xs:string" />
            <xs:attribute name="RootFolder" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ReadSecurity" form="unqualified"
             type="xs:string" />
            <xs:attribute name="WriteSecurity" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Author" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EventSinkAssembly" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EventSinkClass" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EventSinkData" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EmailInsertsFolder" form="unqualified"
             type="xs:string" />
            <xs:attribute name="AllowDeletion" form="unqualified"
             type="xs:string" />
            <xs:attribute name="AllowMultiResponses" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EnableAttachments" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EnableModeration" form="unqualified"
             type="xs:string" />
            <xs:attribute name="EnableVersioning" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Hidden" form="unqualified"
             type="xs:string" />
            <xs:attribute name="MultipleDataList" form="unqualified"
             type="xs:string" />
            <xs:attribute name="Ordered" form="unqualified"
             type="xs:string" />
            <xs:attribute name="ShowUser" form="unqualified"
             type="xs:string" />

The code loads this schema into the DataSet, loads the XmlNode into the XmlDataDocument (by prepending an XML declaration to turn it into a valid document), and then shows the data on the grid.

At this point, you'll be able to inspect the data that SharePoint maintains on each list on the server. The key piece of information for the current example is the ID attribute, which is nothing more than a GUID that uniquely identifies each list. To retrieve the data in an individual list (such as Announcements, Events, or Tasks), you need to send that GUID back in the GetListItems method. The code does this when the user clicks on the grid (placing the code in the MouseUp event ensures that the selection happens before the code runs):

Private Sub dgLists_MouseUp(ByVal sender As Object, _
 ByVal e As System.Windows.Forms.MouseEventArgs) _
 Handles dgLists.MouseUp
    ' Connect to the server
    Dim L As New WSS_Server.Lists
    ' Arguments required by GetListItems
    Dim viewName As String
    Dim query As System.Xml.XmlNode
    Dim viewFields As System.Xml.XmlNode
    Dim rowLimit As String
    Dim queryOptions As System.Xml.XmlNode
    ' Get the items from the list specified
    ' by the current row in the DataGrid
    Dim n As XmlNode = L.GetListItems( _
     dgLists.Item(dgLists.CurrentCell.RowNumber, 2), _
     viewName, query, viewFields, _
     rowLimit, queryOptions)
    ' Get a transform ready
    Dim xslt As XslTransform = New XslTransform
    ' Load the raw XML into an XML document
    Dim xd As XmlDocument = New XmlDocument
    xd.LoadXml("<?xml version='1.0' ?>" & n.OuterXml)
    ' Use the transform to prettify it 
    Dim ms As MemoryStream = New MemoryStream
    xslt.Transform(xd, Nothing, ms, Nothing)
    ' And display the results
    ms.Position = 0
    Dim sr As StreamReader = New StreamReader(ms)
    txtData.Text = sr.ReadToEnd()
End Sub

I can get the contents of the selected list by calling the GetListItems method and supplying the appropriate ID, which comes from the third column (that's column number 2, because of zero-based counting) of the DataGrid in the same row as the current cell. The GetListItems method requires a bunch of arguments that can be used to narrow down the data that it returns. Although these arguments are not optional, they can be empty, so I've just supplied uninitialized variables for them.

Like GetListCollection, GetListItems returns an XmlNode object. The rest of the code in this method shows a useful little trick for "prettyprinting" XML data. If you apply a simple transform (which I've named Identity.xslt) to the original XML, it changes the indentation to make the XML more human-readable without changing any of the data. Here's the contents of Identity.xslt:

<?xml version = "1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="node()|@*">
      <xsl:apply-templates select="node()|@*"/>

That's it! Figure 2 shows the end result of loading up the lists from my server and clicking on the Events list

Data from SharePoint in a VB .NET application

Where Do You Go From Here?

The usefulness of the SharePoint Web services is directly proportional to how much of your organization's information ends up in the new version of SharePoint. But note that the very existence of these Web services is an argument in favor of using SharePoint rather than alternative stores. Anything you store in SharePoint isn't locked up at all; it's open to any client that can make a Web Services call (with the proper authentication, of course). It's nice to see this movement towards open standards and away from closed APIs for things such as appointments, events, and tasks.

About the Author

Mike Gunderloy is the author of over 20 books and numerous articles on development topics, and the lead developer for Larkware. Check out his MCAD 70-305, MCAD 70-306, and MCAD 70-310 Training Guides from Que Publishing. When he's not writing code, Mike putters in the garden on his farm in eastern Washington state.

This article was originally published on November 5, 2003

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date