Guides SharePoint and Web Services

SharePoint and Web Services

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()
    MyBase.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
    ds.ReadXmlSchema("Lists.xsd")
    ' 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"
 targetNamespace="http://schemas.microsoft.com/sharepoint/soap/"
 xmlns_mstns="http://schemas.microsoft.com/sharepoint/soap/"
 
 xmlns_xs="http://www.w3.org/2001/XMLSchema"
 xmlns_msdata="urn:schemas-microsoft-com:xml-msdata"
 attributeFormDefault="qualified" elementFormDefault="qualified">
  <xs:element name="Lists" msdata_IsDataSet="true"
  msdata_EnforceConstraints="False">
    <xs:complexType>
      <xs:choice maxOccurs="unbounded">
        <xs:element name="List">
          <xs:complexType>
            <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" />
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

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
    xslt.Load("Identity.xslt")
    ' 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"
version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

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.

Latest Posts

Related Stories