Friday, February 24, 2012

Creating a SharePoint Site Page With Code-Behind Using Visual Studio 2010

Application Pages versus Site Pages

Using the most basic definition, a site page is customizable by an end user while an application page is not.  That means that a user can pop open SharePoint Designer 2010 and make changes to a site page, but they cannot do this with an application page.  So, what do we mean by “customizable”?  When we open SharePoint Designer 2010 and make changes to a site page, those changes are stored in the database.  The next time we request the page, the page is loaded from the database.  There are more differences than this, but the key difference is really the ability to customize a page.
Coming from an ASP.NET background, we are much more used to coding application pages.  We create a page, drag and drop some controls, write some backend code, hit F5, and see our page do something.  One of the benefits of SharePoint is that we can create page templates that allow an end user to make changes to the page without requiring a developer.  This means they can add web parts, add JavaScript, do neat things with jQuery and XSLT… all the kind of stuff you see on http://endusersharepoint.com
As a developer, you can do some pretty cool stuff to enable the end user with site page templates.

Creating the Site Page

To start with, create an empty SharePoint 2010 project.  I called mine “SampleToDeployAPage”.  When prompted, choose to create this as a farm solution rather than a sandboxed solution.  Once you have the project created, right-click and add a new Module called “CustomPages”.  A folder is created called “CustomPages” with a file called “Sample.txt”.  Rename Sample.txt to “MyPageTemplate.aspx”.  Add the following markup to it:
   1:  <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$" %>
   2:  <%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
   3:  <%@ Register Tagprefix="SharePoint" 
   4:          Namespace="Microsoft.SharePoint.WebControls" 
   5:          Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
   6:  <%@ Register Tagprefix="Utilities" 
   7:          Namespace="Microsoft.SharePoint.Utilities" 
   8:          Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
   9:  <%@ Register Tagprefix="asp" 
  10:          Namespace="System.Web.UI" 
  11:          Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
  12:  <%@ Import Namespace="Microsoft.SharePoint" %>
  13:  <%@ Assembly 
  14:          Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  15:   
  16:  <%@ Page 
  17:      Language="C#"     
  18:      CodeBehind="MyPageTemplate.aspx.cs" 
  19:      Inherits="SampleToDeployAPage.MyPageTemplate, $SharePoint.Project.AssemblyFullName$" 
  20:      masterpagefile="~masterurl/default.master" 
  21:      title="Testing This Page" 
  22:      meta:progid="SharePoint.WebPartPage.Document" %>
  23:   
  24:  <asp:Content id="Content1" runat="server" contentplaceholderid="PlaceHolderMain">
  25:          <asp:Button runat="server" ID="button1" OnClick="Button_Click" />
  26:          <asp:Label runat="server" ID="label1"/>
  27:          <div></div>
  28:          <div></div>
  29:          For more information, visit 
  30:          <a href="http://msdn.microsoft.com/en-us/library/bb964680(v=office.12).aspx">
  31:          Chapter 3: Pages and Design (Part 1 of 2)</a>
  32:  </asp:Content>
It looks like a lot of code, but there’s really very little there.  Line 1 defines the assembly, and Visual Studio 2010 will replace the token placeholder with the full 5-part name of our assembly.  Lines 2 and 12 import a specific namespace (like a using statement in C#), and lines 3-11 register namespace prefixes.  Line 19 references our assembly from the Global Assembly Cache so that SharePoint knows where to find the the class called SampleToDeployAPage.MyPageTemplate.
Now that you’ve created the markup, let’s create the code-behind.  Right click the CustomPages folder and add a new Class called MyPageTemplate.aspx.cs.  We’ll keep this one short:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls;

namespace SampleToDeployAPage
{
    public class MyPageTemplate : WebPartPage
    {
        protected Button button1;
        protected Label label1;

        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void Button_Click(object sender, EventArgs e)
        {
            label1.Text = System.DateTime.Now.ToLongTimeString();
        }
    }
}
Looking at the two samples together, we are simply creating markup that references an assembly in the GAC.  When we click a button, our Button_Click handler is called, and we can set the Text property of a label control in the markup.  This is basic stuff to an ASP.NET developer.  The result in our Solution Explorer pane should look kind of like the following:
image
See the attachment to this post for full source code.

Provisioning a Page Using Visual Studio 2010

Now that we’ve created our page, we need to deploy it to Visual Studio 2010.  When we created our module called “CustomPages”, a file called “elements.xml” was created for us.  That file tells SharePoint how to deploy our page to all of the web front end servers.  We can even provision multiple instances of our template.
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="CustomPages"
          Url="SitePages"
          Path="CustomPages">
    <File Url="MyPageTemplate.aspx"
          Name="SamplePage1.aspx"
          Type="Ghostable"/>
    <File Url="MyPageTemplate.aspx"
          Name="SamplePage2.aspx"
          Type="Ghostable"/>
    <File Url="MyPageTemplate.aspx"
          Name="SamplePage3.aspx"
          Type="Ghostable"/>
  </Module>
</Elements>
In this example, we are provisioning three instances of our page based on the single page template.  We are provisioning this to the SitePages library for our site.  If we deploy the solution as-is, we should see the following in SharePoint Designer 2010.
image
I highly recommend reading Understanding and Creating Customized and Uncustomized Files in Windows SharePoint Services 3.0 for deeper explanation of what is happening here.

Adding Links to the UI for Our Pages

At this point, we can right click the page and choose “Preview in Browser” to see the page.  The URL on my box is http://kirke1/sites/team/SitePages/SamplePage3.aspx, but this may be different for your environment.  I wanted to add a few links to the Site Actions menu, and the easiest way to do this is to use the freely available Community Kit for SharePoint: Development Tools Edition.  It includes a Custom Action project item that makes creating the following XML a snap, but you can simply cut and paste and add the following to the Elements.xml file (as a child of the Elements node) that we created previously.
<CustomAction Description="Custom action for page 1"
                GroupId="SiteActions"
                Id="MySiteAction1"
                Location="Microsoft.SharePoint.StandardMenu"
                Sequence="1000"
                Title="MyCustomAction">
    <UrlAction Url="{SiteUrl}/SitePages/SamplePage1.aspx" />
  </CustomAction>
  <CustomAction Description="Custom action for page 2"
                GroupId="SiteActions"
                Id="MySiteAction2"
                Location="Microsoft.SharePoint.StandardMenu"
                Sequence="1001"
                Title="MyCustomAction">
    <UrlAction Url="{SiteUrl}/SitePages/SamplePage2.aspx" />
  </CustomAction>
  <CustomAction Description="Custom action for page 3"
                GroupId="SiteActions"
                Id="MySiteAction3"
                Location="Microsoft.SharePoint.StandardMenu"
                Sequence="1002"
                Title="MyCustomAction">
    <UrlAction Url="{SiteUrl}/SitePages/SamplePage3.aspx" />
  </CustomAction>
Notice the “SiteUrl” token in the Url attribute of the UrlAction elements that we defined.  There are several token placeholders that you can use to avoid hardcoding paths in your solutions.
See the attachment to this post for full source code.

Marking Our Page Template as Safe

If we deployed everything right now, it would work.  By default, a feature was created to deploy our module, and that feature is scoped to Web, meaning it is scoped to an individual site.  And when we deploy our code and feature definitions, we will see links in the Site Actions menu as advertised, and the pages will render fine.
When we try to customize one of our new pages with SharePoint Designer 2010, we will get a series of errors.
For example, in SharePoint Designer 2010, go to the Site Pages node, right-click SamplePage3.aspx, and choose “Edit File in Advanced Mode”, you can edit the file, but when you save it you will get a series of errors.  Save it as a new file called SamplePage4.aspx and try to preview it in the browser, you are met with the following error:
The base type 'SampleToDeployAPage.MyPageTemplate' is not allowed for this page. The type is not registered as safe.
Remember that SharePoint is built upon ASP.NET.  SharePoint is like ASP.NET with a healthy dose of Code Access Security layered on top.  So, we need to do some security work to tell SharePoint that it’s OK for our page to use code behind.
Right-click the Package node in Visual Studio 2010’s Solution Explorer pane and choose View Template.
image
This lets us add a new configuration entry that marks our code as safe by adding a SafeControls entry to web.config.
<Assemblies>
    <Assembly Location="SampleToDeployAPage.dll"
              DeploymentTarget="GlobalAssemblyCache">
      <SafeControls>
        <SafeControl 
               Assembly="$SharePoint.Project.AssemblyFullName$" 
               Namespace="SampleToDeployAPage" 
               TypeName="MyPageTemplate" Safe="True"/>
      </SafeControls>
    </Assembly>
  </Assemblies>
Yeah, that one’s a freebie :)  This is a pretty cool trick on how to mark types in the current assembly as SafeControls. 
Update:  Waldek Mastykarz pointed out that there’s even an EASIER way to do add SafeControls.  Click the CustomPages module and look at the properties window.  There is a collection called “SafeControls”.  Click that, and add a new SafeControl entry.  I didn’t know this was there, thanks Waldek!
image

Adding web.config Modifications Using SPWebConfigModification

If we deployed everything right now, we’d still get another error if we tried to customize the page and preview it in a browser.  This time, the error has to do with a security setting that enables certain pages to have code behind.
image
I blogged on this some time ago (see Code-blocks are not allowed within this file: Using Server-Side Code with SharePoint).  The problem is that SharePoint has a setting that disallows server-side code with pages.  This is a security feature that is good (you really don’t want end users to arbitrarily inject server-side code), but there may be cases where you are OK with some of your users having this capability.  For instance, you can have a page that is only visible to a small team within your enterprise, and one of the team members is very technical and wants to provide some custom code for SharePoint.  Party on, have fun with it, it saves my team from having to write that code.
To enable this scenario (and enable the Button_Click event handler in our code), we need to add an entry to web.config.  Knowing that we can’t just go to every front-end web server and make the modifications (any admin worth his salt should slap you silly for even thinking about hand-modifying multiple web.config files in a production farm), we should provide this as part of our solution. 
In the Solution Explorer, you will see a node called Features.  Right-click this node and choose “Add Feature”.  That will create a new feature called Feature2.  Double-click this node to bring up the designer for the feature and change its scope to WebApplication.
image
After changing the scope to WebApplication, right-click the feature and choose “Add Event Receiver”.  This will create a code file where you can handle events related to your feature.  We will add code that will make modifications to web.config, adding a new entry to PageParserPaths when the feature is activated, and removing it when the feature is deactivated.
What we want to add is the following:
<SafeMode MaxControls="200" CallStack="false" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
    <PageParserPaths>
       <PageParserPath VirtualPath="/SitePages/SamplePage3.aspx*" CompilationMode="Always" AllowServerSideScript="true" IncludeSubFolders="true" />
    </PageParserPaths>
</SafeMode>
We want to add an entry into web.config that allows the path SitePages/SamplePage3.aspx as one of the pages that allows server-side scripting.  Additionally, we don’t want to add this entry into web.config multiple times, and we want to remove this entry when our feature is deactivated.  Below is the code that enables this.
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Administration;
using System.Collections.ObjectModel;

namespace SampleToDeployAPage.Features.Feature2
{
    /// <summary>
    /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>

    [Guid("122ec36d-8fbf-454b-a514-b0d9ef30af43")]
    public class Feature2EventReceiver : SPFeatureReceiver
    {        
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWebApplication webApplication = properties.Feature.Parent as SPWebApplication;


            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                SPWebConfigModification mod = new SPWebConfigModification();

                mod.Path = "configuration/SharePoint/SafeMode/PageParserPaths";
                mod.Name = "PageParserPath[@VirtualPath='/SitePages/SamplePage3.aspx']";
                mod.Owner = "SampleToDeployAPage";
                mod.Sequence = 0;
                mod.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
                mod.Value = "<PageParserPath VirtualPath='/SitePages/SamplePage3.aspx' CompilationMode='Always' AllowServerSideScript='true' />";

                webApplication.WebConfigModifications.Add(mod);
                webApplication.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
                webApplication.Update();
            });

        }
        

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWebApplication webApplication = properties.Feature.Parent as SPWebApplication;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                Collection<SPWebConfigModification> mods = webApplication.WebConfigModifications;
                int initialModificationsCount = mods.Count;

                for (int i = initialModificationsCount - 1; i >= 0; i--)
                {
                    if (mods[i].Owner == "SampleToDeployAPage")
                    {
                        SPWebConfigModification modToRemove = mods[i];
                        mods.Remove(modToRemove);
                    }
                }

                if (initialModificationsCount > mods.Count)
                {
                    webApplication.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
                    webApplication.Update();
                }

            });
        }

    }
}

Programmatically Creating a SharePoint Content Type

I have been working on a project that requires creating a content type programmatically.  Admittedly, it took me awhile to figure it out.  You can create a content type for SharePoint declaratively in a feature using XML similar to the following:
<?xml version="1.0" encoding="utf-8"?>
<Elements Id="2fdb55a0-75c1-4ad4-b709-82b2e1393f34"
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="0x010100C568DB52D9D0A14D9B2FDCC96666E9F2
007948130EC3DB064584E219954237AF39
0075425CE93BDC404F8B042629FC235785"                   
               Name="TermsAndConditionsType"
               Group="Custom Content Types"
               Description="Custom Content Type for Terms and Conditions">
    <FieldRefs>
      <FieldRef ID="{f55c4d88-1f2e-4ad9-aaa8-819af4ee7ee8}"
                Name="PublishingPageContent" />
    </FieldRefs>
  </ContentType>
</Elements>
That really long ID that is broken into three lines needs to be on a single line, it was formatted for readability.  The challenge is that when we try to delete the content type, we get an error that the content type is part of an application and cannot be deleted.  So, I needed to instead create the content type programmatically.
The above XML works out to the following code:
using (SPSite site = new SPSite("http://sp2010dev:44365"))
{
    SPWeb web = site.RootWeb;
                
    HtmlField field = (HtmlField)web.Fields["Page Content"];

    SPContentTypeId id = new SPContentTypeId("0x010100C568DB52D9D0A14D9B2FDCC96666E9F2
007948130EC3DB064584E219954237AF39
0075425CE93BDC404F8B042629FC235785");
    SPContentType termsAndConditionsType = new
        SPContentType(
            id,            
            web.ContentTypes,
            "TermsAndConditionsType");
                
    web.ContentTypes.Add(termsAndConditionsType);
    termsAndConditionsType = web.ContentTypes[id];
    termsAndConditionsType.Group = "Custom Content Types";
    termsAndConditionsType.Description = "Custom Content Type for Terms and Conditions";
    termsAndConditionsType.Update();
    SPFieldLink l = new SPFieldLink(field) { DisplayName = "Page Content" };
    termsAndConditionsType.FieldLinks.Add(l);
    termsAndConditionsType.Update();                
}

Thursday, February 2, 2012

Building the CAML

Operators

Comparison Operators
Comparison Operators General Meaning
Eq =
Gt
Lt
Geq >=
Leq <=
Neq <> 
Contains Like
IsNull Null
IsNotNull NotNull
BeginsWith Beginning with word
DateRangesOverlap compare the dates in a recurring event with a specified DateTime value, to determine whether they overlap

Fields

The FieldRef element can be any field of the list on which you want to execute the CAML query. If you use the Name attribute you need to specify the internal name of the field. But you can also use the IDattribute to specify the Guid of the field.

Value

The Valueelement specifies the value part of the criterion. The attribute Typeis optional and specifies the data type of the field you want to specify the criterion for. If omitted the data type is considered as being Text. In all other cases you have to specify the Type attribute. DateTime fields are a special case and will be described in more detail later in this article.
If the field type is a Lookup you need to specify the text value.For example you have an Employees list and the Country field is a lookup field referring to the Countries list. In that case an employee living in Belgium will have f.e. following value: #15;Belgium. If you have to query for the employees living in Belgium you will have to write your query as follows:
<Where>
    <Eq>
     <FieldRef Name='Country' />
     <Value Type='Lookup'>Belgium</Value>
  </Eq>
</Where>
You can find this not good coding practice because the name of the country can change in time. In that case you can also query on the id of the country specifying the LookupId attribute in the FieldRef element:
<Where>
  <Eq>
     <FieldRef Name='Country' LookupId='True' />
     <Value Type='Lookup'>15</Value>
  </Eq>
</Where>

Retrieving List Items with CAML using the SharePoint Object Model

If you need to retrieve items from a list when developing web parts, application pages or custom field types you can best use the SPQueryobject from the SharePoint object model. This object is located in the Microsoft.SharePoint namespace of the Microsoft.SharePoint.dll located in the Global Assembly Cache.
Instantiate the object as follows:
SPQuery qry = new SPQuery(); The most important property is the Query property, which needs to be set to your CAML query:
string camlquery = "<OrderBy><FieldRef Name='Country' /></OrderBy><Where>"     + "<Eq><FieldRef Name='LastName' /><Value Type='Text'>Smith</Value></Eq>"     + </Where>"; qry.Query = camlquery; At this point you can execute the query on your list:
SPListItemCollection listItemsCollection = list.GetItems(qry); A small remark with the GetItems method of the SPList instance: this method returns a collection of type SPListItemCollection. It is possible that it is easier working with a DataTable. In that case you can execute the query as follows:
DataTable listItemsTable = list.GetItems(qry).GetDataTable(); The query will not only return all list items that have their last name set to Smith, but also all columns of each list item. In cases you work with large lists it can be important to retrieve a subset of list items containing only the columns you need. In that case you will have to set the ViewFields property of the SPQuery object. You can do this by specifying all columns you want to see returned:
qry.ViewFields = "<FieldRef Name='FirstName' /><FieldRef Name='LastName' />"; This will return the first name and the last name of the retrieved employees, but also the system fields like the ID and the Created date.
The major disadvantage of the SPQuery object is that you can query only one list. If you want to query more than one list you will have to use the SPSiteDataQuery. More on this object in a later article because it earns special attention.
It is common knowledge by now but let me remind you that it’s always a good idea to use SPQuery to retrieve a subset of list items. You can loop through the list item collection to find the list items that match your needs but this will have a serious negative impact on the performance of your work.

Retrieving List Items with CAML using the SharePoint Web Services

If you are developing office clients or any other application that will not run on the server where SharePoint is installed you will need to use the SharePoint Web Services to retrieve (or update) information from SharePoint. If you want to query a list you will need to execute the GetListItems method from the Lists.asmxSharePoint web service.
Working with the SharePoint web services is different in Visual Studio 2005 then in Visual Studio 2008.

Retrieving List Items from the Lists.asmx using Visual Studio 2005

First you have to reference  the web service in your Visual Studio project. If you work with Visual Studio 2005 you have to add a Web Reference to theLists.asmx.
Then you have to instantiate the web service and pass the url of the SharePoint site, plus the location and name of the SharePoint web service. The SharePoint web services are all located in the ISAPI directory of the SharePoint 12 hive but are accessible from outside via the _vti_bin directory.
Initialize the Lists.asmx web service:
 ListService listsWs = new ListService.Lists();
listsWs.Url = siteUrl + @"/_vti_bin/lists.asmx";
Then you have to set the credentials. In case you don’t need to specify a username or password you can proceed as follows:
listsWs.Credentials = System.Net.CredentialCache.DefaultCredentials;
If you have to specify a user name and password:
listsWs.Credentials = new System.Net.NetworkCredential(userName, password);
If you also have to specify a domain, use the other overload:
listsWs.Credentials = new System.Net.NetworkCredential(userName, password, domain);
Then you are ready to call the GetListItems method, which requires the following syntax:
resultNode = _sharepointSite.ListsWSS.GetListItems(listName, viewName,
    queryNode, viewFieldsNode, rowLimit, queryOptionsNode, webID);
Not all arguments are required. Arguments like view name, row limit and web ID are optional.
The query node argument will contain the CAML query as explained in previous sections but need to be enclosed within a <Query> and </Query> tag:
XmlDocument camlDocument = new XmlDocument();
XmlNode queryNode = camlDocument.CreateElement("Query");
queryNode.InnerXml = "<OrderBy><FieldRef Name='Country' /></OrderBy><Where>"
    + "<Eq><FieldRef Name='LastName' /><Value Type='Text'>Smith</Value></Eq>"
    + </Where>";
The same applies to the ViewFields node:
XmlNode viewFieldsNode = camlDocument.CreateElement("ViewFields");
viewFieldsNode.InnerXml = "<FieldRef Name='FirstName' />"
    + "<FieldRef Name='LastName' />";
As you will have noticed, you also need a QueryOptions node. This node will be explained later in this series. If you have no QueryOptions to specify you can pass in an empty node:
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");

Retrieving List Items from the Lists.asmx using Visual Studio 2008

But in case you are working with Visual Studio 2008 you will have to add a Service Reference to theLists.asmxweb service. If you don’t want to work asynchronously you have to uncheck the Generate Asynchronous Operations option in the Advanced dialog. When closing the dialog box Visual Studio automatically adds an app.config or web.config file. Open this file and locate the security section. The following XML is generated automatically:
<security mode="None">
    <transport clientCredentialType="None" proxyCredentialType="None"
        realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Replace it with the following:
<security mode="TransportCredentialOnly">
  <transport clientCredentialType="Ntlm"/>
</security>
Return to your code and instantiate the web service:
ListsWS.ListsSoapClient ws = new ListsWS.ListsSoapClient();
You also have to set the necessary credentials. If you can work with the default credentials you can write the following:
 ws.ClientCredentials.Windows.ClientCredential =
       System.Net.CredentialCache.DefaultNetworkCredentials;
 ws.ClientCredentials.Windows.AllowedImpersonationLevel =
       System.Security.Principal.TokenImpersonationLevel.Impersonation;
If necessary you can also pass user name, password and domain:
 ws.ClientCredentials.Windows.ClientCredential =
       new System.Net.NetworkCredential("Administrator", "secret", "U2UCOURSE");
 ws.ClientCredentials.Windows.AllowedImpersonationLevel =
       System.Security.Principal.TokenImpersonationLevel.Impersonation;
If necessary you can set the URL to the web service dynamically:
 ws.Endpoint.Address =
     new System.ServiceModel.EndpointAddress(
     "http://wss.u2ucourse.com/_vti_bin/lists.asmx");
Now you are ready to call the GetListItems method of the web service. There is no difference in calling this method from within Visual Studio 2005:
XmlDocument camlDocument = new XmlDocument();
 XmlNode queryNode = camlDocument.CreateElement("Query");
queryNode.InnerXml = "<OrderBy><FieldRef Name='Country' /></OrderBy><Where>"
    + "<Eq><FieldRef Name='LastName' /><Value Type='Text'>Smith</Value></Eq>"
    + </Where>";
 XmlNode viewFieldsNode = camlDocument.CreateElement("ViewFields");
viewFieldsNode.InnerXml = "<FieldRef Name='FirstName' />"
    + "<FieldRef Name='LastName' />";
 XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
 resultNode = _sharepointSite.ListsWSS.GetListItems(listName, viewName,
    queryNode, viewFieldsNode, rowLimit, queryOptionsNode, webID);
The returned XML is rather complex and needs some special attention. I will come back on this in a later article.

Query Options

Executing a query is not only about CAML. When working with the SPQuery object you can set different properties to influence the returned list items. When working with the SharePoint web services, these options are translated into CAML and are part of the QueryOptions element.

RowLimit

Setting this property limits the number of rows returned in the result set.
When working with the SPQuery object:
qry.RowLimit = 10;
When working with the GetListItems method of the Lists.asmx web service:
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
queryOptionsNode.InnerXml = "<RowLimit>10</RowLimit>";

IncludeMandatoryColumns

When this Boolean property is set to True, the result set will not only return the columns as defined in the ViewFields property, but also the columns that you defined in the list as required.
When working with the SPQuery object:
qry.IncludeMandatoryColumns = true;
When working with the GetListItems method of the Lists.asmx web service:
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
queryOptionsNode.InnerXml =
    "<IncludeMandatoryColumns>True</IncludeMandatoryColumns>";

DatesInUtc

Setting this Boolean property specifies whether the query returns dates in Coordinated Universal Time (UTC) format. The syntax is similar to that of the previously described property.

ExpandUserField

When you omit this property or set it to false, user fields will return the login name of the user.
Setting this Boolean property to true  (or include it in the QueryOptions node), user fields are returned as follows:
Karine Bosch,#U2UCOURSE\karine,#karine@U2UCOURSE.COM,#,#Karine Bosch
The returned value includes the login name, e-mail address, Session Initiation Protocol (SIP) address, and title, when present, which causes a user field to behave as a multilookup field.  The syntax is similar to that of the previously described property.
There are some other query options to set but they will be explained in detail in the next section.

Special Types of Queries

Some special types of lists require more specialized CAML queries. In some cases it only affects the CAML but in other cases you have to set extra SPQuery properties. If you execute this query against the Lists web service it will affect another argument of the GetListItems method, i.e. the QueryOptions argument.

Building queries for working with Folders

A first variant I will explain is how you can work with folders and sub folders. A folder is a special list item on a list or document library. If you execute a standard CAML query you will end up with list items from the root folder.
If you want to query all folders and sub folders of a list or document library, you have to define extra query options. If you are working with the object model you have to set the ViewAttributes property of the SPQuery object as follows:
qry.ViewAttributes = "Scope='Recursive'";
If you work with GetListItems method of the Lists.asmx SharePoint web service, you have to define an extra node with the QueryOptions element:
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
queryOptionsNode.InnerXml = "<ViewAttributes Scope=\"Recursive\" />";
If you want to query a specific sub folder using the SPQuery object, you have to set the Folder property:
qry.Folder = list.ParentWeb.GetFolder("Folders DocLib/2008");
When working with the web services you have to do the following:
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
queryOptionsNode.InnerXml = "<Folder>Folders DocLib/2008</Folder>";

Building Queries for working with DateTime Values

Filtering on DateTime fields also requires some extra attention. First of all when querying for a specific date, you have to use the SharePoint datetime notation:
<Where>
   <Ge>
        <FieldRef Name="StartDate" />
        <Value Type="DateTime">2008-08-10T10:00:00Z</Value>
   </Ge>
</Where>
But in this case the date is hard coded and the time part will not be taken into account. This query will return all list items with a start date as of 10 August 2008, also those starting before 10 o’clock. If you want your query to take into account the time part, you have to use a special attribute IncludeTimeValue that you can set on the FieldRef element:
<Where>
   <Ge>
        <FieldRef Name="StartDate" IncludeTimeValue="TRUE" />
        <Value Type="DateTime">2008-08-10T10:00:00Z</Value>
   </Ge>
</Where>
This query will return all list items with a start date as of 10 August 10 o’clock.
As already said, this way the date is hard coded. If you want your query a bit more dynamic, you can always use the element Today.
<Where>
   <Ge>
        <FieldRef Name="StartDate" />
        <Value Type="DateTime"><Today /></Value>
   </Ge>
</Where>
Today will not take a time part into account. Unfortunately a Now element doesn’t exist.
You can also add or subtract a number of days from today’s date. In that case you have to add the Offset attribute to the Today element. The Offset attribute accepts a positive value for adding days and a negative value for subtracting days.
 <Where>
   <Ge>
        <FieldRef Name="StartDate" />
        <Value Type="DateTime"><Today Offset="10" /></Value>
   </Ge>
</Where>
As all this is pure CAML, the query is the same whether you work with the object model or the SharePoint web services.

Building Queries for Calendar Lists

Calendar lists also require a little more attention. A calendar list is based on the Event content type. Normal events can be retrieved with the usual CAML queries. It’s only when you start working with recurring events (events that occur once a day or twice a week or month) that you run into problems.
The Event content type defines a field named fRecurrence, which is set to 1 when a recurring event is created.
Defining a recurring event
Defining a recurring event
When the Calendar view is rendered a recurring event is split into a number of event instances, one for each recurrence.
Calendar view showing event instances for recurring event
Calendar view showing event instances for recurring event
The definition of the recurrence is XML stored in another field defined by the Event content type, i.e. RecurrenceData. An example of such a definition looks as follows:
<recurrence>
   <rule>
     <firstDayOfWeek>su</firstDayOfWeek>
     <repeat>
        <weekly mo="TRUE" we="TRUE" weekFrequency="1" />
     </repeat>
     <repeatForever>FALSE</repeatForever>
   </rule>
</recurrence>
Fortunately you don’t have to parse the XML yourself to get the actual instances of the recurring event. You can use a combination of CAML syntax and query options to achieve this.
When working with the SPQuery object you need to set the ExpandRecurrences property to true. You also have to specify a date in the CalendarDate property. This date will be used to compare the recurring event instances.
Next you have to add a DateRangesOverlap element to the Where clause of the CAML query. This element is used in queries to compare the dates in a recurring event with the date specified in the CalendarDateproperty to see whether they overlap. The CAML looks as follows:
<Where>
   <DateRangesOverlap>
      <FieldRef Name=\"EventDate\" />
      <FieldRef Name=\"EndDate\" />
      <FieldRef Name=\"RecurrenceID\" />
      <Value Type=\"DateTime\"><Month /></Value>
   </DateRangesOverlap>
</Where>
The <Month /> element is used to specify that all occurrences within a month need to be returned. You can also specify Day, Week or Year.
In case you need to work with the GetListItems method of the Lists.asmx web service, you translate the query options into XML:
XmlNode queryOptionsNode = camlDocument.CreateElement("QueryOptions");
queryOptionsNode.InnerXml = "<ExpandRecurrences>TRUE</ExpandRecurrences>"
 + "<CalendarDate>2008-08-12T10:00:00Z</CalendarDate>";
Read more about Calendar lists here: http://blogs.msdn.com/sharepoint/archive/2007/05/14/understanding-the-sharepoint-calendar-and-how-to-export-it-to-ical-format.aspx

 Example: Contains, And, BeginsWith

<Where>
   <And>
       <BeginsWith>
              <FieldRef Name="Conference"/> 
              <Value Type="Note">Morning</Value>
       </BeginsWith>
       <Contains>
              <FieldRef Name="Conference" />
              <Value Type="Note">discussion session</Value>
       </Contains>
   </And>
</Where>
Example: DateRangesOverlap
<Where> 

     <DateRangesOverlap> 

          <FieldRef Name="EventDate"></FieldRef> 

          <FieldRef Name="EndDate"></FieldRef> 

          <FieldRef Name="RecurrenceID"></FieldRef> 

            <Value Type="DateTime"> 

              <Now/> 

            </Value> 

     </DateRangesOverlap> 

</Where>
Logical Joins:
Logical Joins Comments
And Used within the ‘Where’ element to group filters in a query for a view
Or Used within the ‘Where’ element to group filters in a query for a view
Example: And
<Where>

   <And> 

     <Neq> 

        <FieldRef Name="Status"></FieldRef> 

        <Value Type="Text">Completed</Value> 

     </Neq> 

     <IsNull> 

        <FieldRef Name="Sent"></FieldRef> 

     </IsNull> 

   </And> 

</Where> 
Order/Group Operators:
Order/Group Operators Comments
OrderBy Determines the sort order for a query. The OrderBy element contains a group of FieldRef elements
I.e. <OrderBy><FieldRef Name="Title" Ascending="TRUE">
</FieldRef></OrderBy>
GroupBy Contains a Group By section for grouping the data returned through a query in a list view
Example: OrderBy
<OrderBy> 

       <FieldRef Name="Modified" Ascending="FALSE"></FieldRef> 

</OrderBy> 

<Where> 

  <Or> 

    <Neq> 

      <FieldRef Name="Status"></FieldRef> 

      <Value Type="Text">Completed</Value> 

    </Neq> 

    <IsNull> 

      <FieldRef Name="Status"></FieldRef> 

    </IsNull> 

  </Or> 

</Where>
Example: GroupBy
<GroupBy> 

      <FieldRef Name="Modified"/> 

</GroupBy> 

<Where> 

   <Or> 

      <Neq> 

          <FieldRef Name="Status"></FieldRef> 

          <Value Type="Text">Completed</Value> 

      </Neq> 

      <IsNull> 

          <FieldRef Name="Status"></FieldRef> 

      </IsNull> 

   </Or> 

</Where> 
Important: This is very important thing to keep in mind, because SPQuery will be assigned as a string so it wont show compile time error though it may have tag syntax error, not in order, escape sequence error, etc. Escape sequence: The ScriptEncode method escapes characters that would otherwise conflict with script.
Original
Replacement
"
\"
\
\\
+
\u002b
\u003e
\u003c
'
\u0027
Example:
<FieldRef Name=\"Checkbox\"></FieldRef> <Value Type=\"bit\">1</Value>