Getting Started with SharePoint Web Services using LINQ to XML
[Blog Map]
Web services are one of the most effective and convenient ways for casual developers to access SharePoint lists and document libraries. They have a reputation for being a bit difficult; LINQ to XML can make them easier to use. This post presents the basic steps for getting started with Windows SharePoint Services Web Services using LINQ to XML (either C# or VB).
In several upcoming posts, I’ll present some more information about using web services, as well as more notes on the code presented in this post. There are some interesting and easy ways to explore SharePoint web services using LINQ to XML. However, before addressing more involved scenarios, I want to make sure that you can get started easily.
First, a few points about SharePoint web services. They can be disabled for a SharePoint site, but by default, they are enabled. In most cases, it is easy to use them; if you have permissions to manually create and modify documents for a site, you probably can use web services to do so too.
One important feature of SharePoint that enables effective collaboration is the My Site feature. For an introduction to your My Site, see this Office Online article. Chances are, if you have a My Site in your company, you can use web services to programmatically access it. In an upcoming project, I plan to use the SharePoint collaboration features to make managing the project easier. Then I'll write a little C# program that collects information from lists and document libraries (using web services) and produces a nicely formatted status report as an Open XML Wordprocessing document, and then places the report into an appropriate document library.
Here are the steps:
Create a new Windows Console application (either C# or VB).
Important note: Pay attention to the name that you give your application, as the classes created to access the SharePoint web services will be in the namespace of your application. For this example, name the application SPWebServicesExample.
Add a reference to your SharePoint web service. Select Project, Add Service Reference…
Click the Advanced button:
Click the ‘Add Web Reference’ button:
In the Add Web Reference dialog box, enter the URL of the ‘Lists’ web service. Web services in SharePoint are located in the ‘_vti_bin’ directory under the relevant site. If you are using web services to access your My Site, then enter the URL: ‘http://my/sites/your-alias- here/_vti_bin/lists.asmx’. If you are using web services to access a SharePoint site located at http://ourteamsite, the URL will be ‘http://ourteamsite/_vti_bin/lists.asmx’.
Click the Go button to confirm the URL. If you have entered a valid URL, then this dialog box tells you that it found a web service. The dialog box will be populated with the various operations available in the web service.
Change the web reference name to something relevant. For accessing the Lists web service, a good web reference name is ‘ListsWebService’.
Click the Add Reference button to add this reference to your project.
Following is a small example to get all of the lists and list items in a site. The example creates a small XML "report" that contains relevant data on the lists and items. In addition to the listing on this page, I've attached the code to this post.
In general, when using this code as boilerplate, you have to remember to update three things (all highlighted in the listing below):
-
The namespace for your web service proxy class (two occurrences)
-
The web reference name (two occurrences)
-
The URL of the SharePoint site that you want to access
Note that if you used the names suggested earlier, you will not need to update the first two items, as the web service proxy will already be set to “SPWebServicesExample” and the web reference name will already be set to “ListsWebService”.
There are a couple of notes to make about the following code:
-
-
When printing the "Report" XML tree to the console, the code uses the technique that I described in "Align Attributes when Formatting XML using LINQ to XML". To make it more convenient to convert an XML tree to a string where attributes are aligned, in this example I wrote an extension method, ToStringAlignAttributes.
-
It is more convenient to use LINQ to XML instead of XmlDocument for accessing web services. You can write simpler, easier to read code when creating the XML that you pass as arguments to operations. In particular, for this purpose, VB XML literals rock! And the code to query the XML returned by the web service is much easier to write, in my opinion.
I'll be blogging more about how to use these web services. There's a lot that you can do with them. I am especially enthused about taking advantage of what you can do with Open XML and the Open XML SDK. Stay tuned...
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace SPWebServicesExample
{
public static class MyExtensions
{
public static XElement GetXElement (this XmlNode node)
{
XDocument xDoc = new XDocument();
using (XmlWriter xmlWriter = xDoc.CreateWriter())
node.WriteTo(xmlWriter);
return xDoc.Root;
}
public static XmlNode GetXmlNode (this XElement element)
{
using (XmlReader xmlReader = element.CreateReader())
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlReader);
return xmlDoc;
}
}
public static string ToStringAlignAttributes(this XElement element)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
StringBuilder stringBuilder = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder, settings))
element.WriteTo(xmlWriter);
return stringBuilder.ToString ();
}
}
class Program
{
static void Main(string[] args)
{
XNamespace s = "http://schemas.microsoft.com/sharepoint/soap/";
XNamespace rs = "urn:schemas-microsoft-com:rowset";
XNamespace z = "#RowsetSchema";
// Make sure that you use the correct namespace, as well as the correct reference
// name. The namespace (by default) is the same as the name of the application
// when you created it. You specify the reference name in the Add Web Reference
// dialog box.
//
// Namespace Reference Name
// | &nb sp; |
// V &nb sp; V
SPWebServicesExample.ListsWebService.Lists lists =
new SPWebServicesExample.ListsWebService.Lists ();
// Make sure that you update the following URL to point to the Lists web service
// for your SharePoint site.
lists.Url = "http://my/sites/your-alias-here/_vti_bin/Lists.asmx";
//lists.Url = "http://xyzteamsite/_vti_bin/Lists.asmx";
lists.Credentials = System.Net.CredentialCache.DefaultCredentials;
XElement queryOptions = new XElement("QueryOptions",
new XElement("Folder"),
new XElement("IncludeMandatoryColumns", false)
);
XElement viewFields = new XElement("ViewFields");
XElement listCollection = lists.GetListCollection().GetXElement();
XElement report = new XElement("Report",
listCollection
.Elements(s + "List")
.Select(
l =>
{
return new XElement("List",
l.Attribute("Title"),
l.Attribute ("DefaultViewUrl"),
l.Attribute("Description"),
l.Attribute("DocTemplateUrl"),
l.Attribute("BaseType"),
l.Attribute("ItemCount"),
l.Attribute("ID"),
lists.GetListItems((string) l.Attribute("ID"), "", null,
viewFields.GetXmlNode(), "", queryOptions.GetXmlNode(), "")
.GetXElement()
.Descendants(z + "row")
.Select(r =>
new XElement("Row",
r.Attribute("ows_Title"),
r.Attribute("ows_ContentType"),
r.Attribute("ows_FSObjType"),
r.Attribute("ows_Attachments"),
r.Attribute("ows_FirstName"),
r.Attribute("ows_LinkFilename"),
r.Attribute("ows_EncodedAbsUrl"),
r.Attribute("ows_BaseName"),
r.Attribute("ows_FileLeafRef"),
r.Attribute("ows_FileRef"),
r.Attribute("ows_ID"),
r.Attribute("ows_UniqueId"),
r.Attribute("ows_GUID")
)
)
);
}
)
);
Console.WriteLine (report.ToStringAlignAttributes());
}
}
}
VB
Imports System.Xml
Imports System.Text
Module Module1
<System.Runtime.CompilerServices.Extension()> _
Public Function GetXElement (ByRef node As XmlNode) As XElement
dim xDoc as XDocument = new XDocument()
using xmlWriter as XmlWriter = xDoc.CreateWriter()
node.WriteTo(xmlWriter)
End Using
return xDoc.Root
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function GetXmlNode (ByRef element As XElement) As XmlNode
Using xmlReader as XmlReader = element.CreateReader()
Dim xmlDoc As XmlDocument = New XmlDocument
xmlDoc.Load(xmlReader)
Return xmlDoc
End Using
End Function
<System.Runtime.CompilerServices.Extension()> _
Public Function ToStringAlignAttributes(ByVal element As XElement) As String
Dim settings As XmlWriterSettings = New XmlWriterSettings()
settings.Indent = True
settings.OmitXmlDeclaration = True
settings.NewLineOnAttributes = True
Dim stringBuilder As StringBuilder = New StringBuilder()
Using xmlWriter As XmlWriter = xmlWriter.Create(stringBuilder, settings)
element.WriteTo(xmlWriter)
End Using
Return stringBuilder.ToString()
End Function
Sub Main()
Dim s as XNamespace = "http://schemas.microsoft.com/sharepoint/soap/"
Dim rs as XNamespace = "urn:schemas-microsoft- com:rowset"
Dim z as XNamespace = "#RowsetSchema"
' Make sure that you use the correct namespace, as well as the correct reference name.
' The namespace (by default) is the same as the name of the application when you
' created it. You specify the reference name in the Add Web Reference dialog box.
'
' Namespace Reference Name
' | |
' V V
Dim lists As SPWebServicesExample.ListsWebService.Lists = _
New SPWebServicesExample.ListsWebService.Lists()
' Update the following URL to point to the Lists web service
' for your SharePoint site.
lists.Url = http://my/sites/your-alias-here/_vti_bin/Lists.asmx
'lists.Url = "http://xyzteamsite/_vti_bin/Lists.asmx";
lists.Credentials = System.Net.CredentialCache.DefaultCredentials
Dim queryOptions = _
<QueryOptions>
<Folder/>
<IncludeMandatoryColumns>false</IncludeMandatoryColumns>
</QueryOptions>
Dim viewFields = <ViewFields/>
dim listCollection as XElement = lists.GetListCollection().GetXElement()
Dim report as XElement = _
<Report>
<%= listCollection _
.Elements(s + "List") _
.Select( Function(l) _
new XElement("List", _
l.Attribute("Title"), _
l.Attribute("DefaultViewUrl"), _
l.Attribute("Description"), _
l.Attribute("DocTemplateUrl"), _
l.Attribute("BaseType"), _
l.Attribute("ItemCount"), _
l.Attribute("ID"), _
lists.GetListItems(l.Attribute("ID"), "", Nothing, _
viewFields.GetXmlNode(), "", queryOptions.GetXmlNode(), "") _
.GetXElement() _
.Descendants(z + "row") _
.Select (Function(r) _
new XElement ("Row", _
r.Attribute("ows_Title"), _
r.Attribute("ows_ContentType"), _
r.Attribute("ows_FSObjType"), _
r.Attribute("ows_Attachments"), _
r.Attribute("ows_FirstName"), _
r.Attribute("ows_LinkFilename"), _
r.Attribute("ows_EncodedAbsUrl"), _
r.Attribute("ows_BaseName"), _
r.Attribute("ows_FileLeafRef"), _
r.Attribute("ows_FileRef"), _
r.Attribute("ows_ID"), _
r.Attribute("ows_UniqueId"), _
r.Attribute("ows_GUID") _
) _
) _
) _
) %>
</Report>
Console.WriteLine (report.ToStringAlignAttributes())
End Sub
End Module
After you build and run this example, your output should look like this. Note that for even a small SharePoint site, this may run several thousand lines long, so you may have to redirect the output to a file or change the screen buffer height on the command prompt window to view it all.
<Report>
<List
Title="AList"
DefaultViewUrl="/sites/ericwhit/AList/Forms/AllItems.aspx"
Description="AList"
DocTemplateUrl="/sites/ericwhit/AList/Forms/template.dotx"
BaseType="1"
ItemCount="0"
ID="{AA12AA75-2422 -48BB-B41A-267C61D7A54F}" />
<List
Title="Eric White's Wiki"
DefaultViewUrl="/sites/ericwhit/Eric Whites Wiki/Forms/AllPages.aspx"
Description="Wiki"
DocTemplateUrl=""
BaseType="1"
ItemCount="3"
ID="{AA0A2753-5A94 -42C1-BAA7-66DD1409CD3E}">
<Row
ows_ContentType="Wiki Page"
ows_FSObjType="2;#0"
ows_LinkFilename="Home.aspx"
ows_EncodedAbsUrl="http://my/sites/ericwhit/Eric%20Whites%20Wiki/Home.aspx"
ows_BaseName="Home"
ows_FileLeafRef="2;#Home.aspx"
ows_FileRef="2;#sites/ericwhit/Eric Whites Wiki/Home.aspx"
ows_ID="2"
ows_UniqueId="2;#{AA6833E4-98F2-42C4-9355-6DF2453DC7D1}"
ows_GUID="{AAEA7CFF-9FE1-47F9-8C48-94B631289D0F}" />
<Row
...