Getting Started with SharePoint Web Services using LINQ to XML
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).
This blog is inactive.
New blog: EricWhite.com/blogBlog TOCIn 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:
My Site https://my/sites/your-alias- here/_vti_bin/lists.asmx https://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:
- The code to create the report uses the LINQ to XML idiom that I detailed in the blog post titled ''Writing Succinct Code to move XElement and XAttribute Objects from One LINQ to XML Tree to Another".
- 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.
- To convert the LINQ to XML trees to XmlNode (and back), the codes uses the approach from "Convert XElement to XmlNode (and Convert XmlNode to XElement) ".
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
{
publicstaticclassMyExtensions
{
publicstaticXElement GetXElement (thisXmlNode node)
{
XDocument xDoc = newXDocument();
using (XmlWriter xmlWriter = xDoc.CreateWriter())
node.WriteTo(xmlWriter);
return xDoc.Root;
}
publicstaticXmlNode GetXmlNode (thisXElement element)
{
using (XmlReader xmlReader = element.CreateReader())
{
XmlDocument xmlDoc = newXmlDocument();
xmlDoc.Load(xmlReader);
return xmlDoc;
}
}
publicstaticstring ToStringAlignAttributes(thisXElement element)
{
XmlWriterSettings settings = newXmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
StringBuilder stringBuilder = newStringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder, settings))
element.WriteTo(xmlWriter);
return stringBuilder.ToString ();
}
}
classProgram
{
staticvoid Main(string[] args)
{
XNamespace s = "https://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
// | & |
// V & V
SPWebServicesExample.ListsWebService.Lists lists =
// Make sure that you update the following URL to point to the Lists web service
// for your SharePoint site.
lists.Url = "https://my/sites/your-alias-here/_vti_bin/Lists.asmx";
//lists.Url = "https://xyzteamsite/_vti_bin/Lists.asmx";
lists.Credentials = System.Net.CredentialCache.DefaultCredentials;
XElement queryOptions = newXElement("QueryOptions",
newXElement("Folder"),
newXElement("IncludeMandatoryColumns", false)
);
XElement viewFields = newXElement("ViewFields");
XElement listCollection = lists.GetListCollection().GetXElement();
XElement report = newXElement("Report",
listCollection
.Elements(s + "List")
.Select(
l =>
{
returnnewXElement("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 =>
newXElement("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());
}
}
}
new SPWebServicesExample.ListsWebService. Lists ();
VB
Imports System.Xml
Imports System.Text
Module Module1
<System.Runtime.CompilerServices.Extension()> _
PublicFunction GetXElement (ByRef node As XmlNode) As XElement
dim xDoc as XDocument = new XDocument()
using xmlWriter as XmlWriter = xDoc.CreateWriter()
node.WriteTo(xmlWriter)
EndUsing
return xDoc.Root
EndFunction
<System.Runtime.CompilerServices.Extension()> _
PublicFunction GetXmlNode (ByRef element As XElement) As XmlNode
Using xmlReader as XmlReader = element.CreateReader()
Dim xmlDoc As XmlDocument = New XmlDocument
xmlDoc.Load(xmlReader)
Return xmlDoc
EndUsing
EndFunction
<System.Runtime.CompilerServices.Extension()> _
PublicFunction ToStringAlignAttributes(ByVal element As XElement) AsString
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)
EndUsing
Return stringBuilder.ToString()
EndFunction
Sub Main()
Dim s as XNamespace = "https://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 = https://my/sites/your-alias-here/_vti_bin/Lists.asmx
'lists.Url = "https://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())
EndSub
EndModule
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="https://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
...
Comments
Anonymous
January 05, 2009
PingBack from http://www.codedstyle.com/getting-started-with-sharepoint-wss-web-services-using-linq-to-xml/Anonymous
January 09, 2009
Here is a list on links that I want to share with you. LINQ for Office Developers Some Office solutionsAnonymous
February 22, 2009
XNamespace s = "http://schemas.microsoft.com/sharepoint/soap/"; XNamespace rs = "urn:schemas-microsoft-com:rowset"; XNamespace z = "#RowsetSchema"; => How to know these namespaces exactly, Eric? Could you show me how many kind of namespaces there are? Thanks.Anonymous
February 23, 2009
The comment has been removedAnonymous
February 24, 2009
VB samples "Function(l)" and "Function(r)" not workingAnonymous
March 07, 2009
Hi Eric, novice... managed to complete everything in your example... build goes ok with no errors... however when start debugging the console window comes up but nothing ever comes back... is there something basic that needs to be added to the project that I missed?Anonymous
April 27, 2009
I've been trying to find out how to add a 'web reference' via the 'service reference' option in VS2008 and this really helped. Many thanks!Anonymous
April 29, 2009
Thanks so much for the complete example, works perfectly for me! @Glynn: How long did you wait to see if anything came up? It takes my machine 30s - 1min to actually start writing the XML to the console.Anonymous
February 18, 2010
Hi Eric, great post. I'm now thinking about reusing this code for other SP web services, for example the "AddList" method of the Lists web service. I have an idea as to how to start, for example by taking the large Linq to XML statement and putting it in a method called CallGetListsCollection and return the XElement. I suppose I'll just start hacking away and see what I come up with, but wonder if you had any thoughts on whether there's a clean way to reuse such code for different methods like "AddList", "CreateContentType" etc.Anonymous
February 21, 2010
Hi David, The approach that I would take is to parameterize the large LINQ to XML functional construction statement. However, this statement will, for the most part, be unique to the particular web service. I would have different methods for each web service, each with their own code to create the XML. -EricAnonymous
February 22, 2010
Thanks for that advice, much appreciated. It will be a good exercise for me.Anonymous
June 03, 2010
Nice article. For an object which does the Linq to XML (using VB.Net which supports XML Literals -- you should check it out) see this link: sqlsrvintegrationsrv.codeplex.com/.../53230Anonymous
December 17, 2010
Thanks, I'd love an example of using Query service to return search results.Anonymous
February 08, 2012
Hi, When I enter the code I get an error for the lists URL reference in the code. The URL does resolve in a browser or click on the link in the code. The error I am getting is "Error 2 Cannot implicitly convert type 'string' to 'SPWebServicesExample.ListsWebService.Lists' I am using the namespace conventions as per you article. Please help