SharePoint and Web Services by sreekanthreddy


More Info
									SharePoint and Web Services
By Mike Gunderloy

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
      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
      http://server/_vti_bin/Sites.asmx - Contains a single method to retrieve site
      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.

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=""
  <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
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.

To top