Not all server-side objects are available
within the Client Object Model. Generally speaking, all objects from
SPSite downward are included. No representations of administrative
classes, such as those found in the Microsoft.SharePoint.Administration
namespace, are included.
The Client Object Model is encapsulated in four namespaces:
Microsoft.SharePoint.Client
This namespace contains representations of many commonly used server
objects such as SPSite, SPWeb, SPList, SPListItem, and SPField. These
objects are implemented in the Client Object Model without the SP
prefix—so, for example, SPSite in the Server Object Model maps to Site
in the Client Object Model. This is the same for all variants of the
Client Object Model. The exception to this rule is the SPContext
object, which is represented as ClientContext in the Client Object
Model. The ClientContext object is a key component in the Client Object
Model and exposes functionality that has no direct counterpart in the
SPContext server-side object. We’ll cover ClientContext in greater
detail in the next section.
Microsoft.SharePoint.Client.Utilities
This namespace contains representations of a few commonly used
server-side utility classes. Those included are HttpUtility, which maps
to SPHttpUtility on the server side; PrincipalInfo, which maps to
SPPrincipalInfo on the server side; and Utility, which maps to
SPUtility on the server side.
Microsoft.SharePoint.Client.WebParts
This namespace contains representations of server-side objects that are
commonly used in the management of web parts. Using the classes in this
namespace, you can access and modify web parts and web part pages.
Microsoft.Sharepoint.Client.Workflow
This namespace contains representations of a number of server-side
classes concerned with the operation of workflows. Using the classes in
this namespace, you can manage workflow associations and templates.
ClientContext
When writing code that uses the Server Object Model, you generally start with something like this:
string GetWebName(string url)
{
using (SPSite site = new SPSite(url))
{
using (SPWeb web=site.OpenWeb(url))
{
return "Title:" + web.Title + ", Description:" + web.Description;
}
}
}
Or, if you’re writing code for a web part, you can use the following:
string GetWebName(string url)
{
return "Title:" + SPContext.Current.Web.Title
+ ", Description:" + SPContext.Current.Web.Description;
}
Let’s take a look at how to achieve a similar result by using the Silverlight Client Object Model:
Using the SilverlightCOMDemo project that we added earlier, in MainPage.xaml, add a button control and a label control.
Select the button control and then, using the Properties pane, set the Content to Get Web Details.
Switch to the Events tab in the Properties pane and add Button_Click as the hander for the Click event, as shown:
Switch to MainPage.xaml.cs and add the following code:
private void Button_Click(object sender, RoutedEventArgs e)
{
ClientContext ctx=new ClientContext("Your Site URL Here");
Web web = ctx.Web;
ctx.Load(web);
ctx.ExecuteQueryAsync((s, args) =>
{
Dispatcher.BeginInvoke(() => {
label1.Content = "Title:" + web.Title
+ ", Description:" + web.Description; });
}, null);
}
Build
the SilverlightCOMDemo project and then deploy the solution. If a
Deployment Conflict dialog is presented indicating a conflict in the
SilverlightControls project item, check the Do Not Prompt Me Again For
These Items checkbox and click Resolve Automatically. The conflict
occurs because list instances are not automatically removed when a
solution is retracted.
Navigate
to the Silverlight Test page that we created earlier: http://<your
Server Url>/Chapter4/SitePages/SilverlightTest.aspx.
If we’re using the JavaScript version of the object model, we could take the following steps:
Using SharePoint Designer, edit the JavascriptTest.aspx page that we created earlier.
Above the WebPartPages:WebPartZone at the bottom of the page, insert the following HTML:
<script type="text/javascript"
src="../SilverlightControls/JScriptTest.js" ></script>
<input name="Button1" type="button" value="Get Web Details"
onclick="Button_Click()"></input>
<div id="DemoConsole"></div>
In the JScriptTest.js file that we added earlier, add the following code:
/// <reference path="C:\Program Files\Common Files\Microsoft Shared\ →
Web Server Extensions\14\TEMPLATE\LAYOUTS\MicrosoftAjax.js" />
/// <reference path="C:\Program Files\Common Files\Microsoft Shared\Web →
Server Extensions\14\TEMPLATE\LAYOUTS\SP.debug.js" />
function Button_Click() {
var ctx = new SP.ClientContext.get_current();
var web = ctx.get_web();
ctx.load(web);
ctx.executeQueryAsync(function(s,args) {
var console = document.getElementById('DemoConsole');
console.innerHTML = "Title:" + web.get_title()
+ ", Description:" + web.get_description();
},
null);
}
Deploy
the solution, and then navigate to the JavaScript Test page that we
created earlier: http://<your Server
Url>/Chapter4/SitePages/JavaScriptTest.aspx.
The
important thing to notice in these samples is the use of the
ClientContext object as the entry point to the Client Object Model.
When called by the Silverlight sample, a URL is required, but the
JavaScript sample doesn’t need a URL because the URL is derived from
the current page. Also notice the use of the reference elements. These
allow Visual Studio 2010 to provide IntelliSense support for the Client
Object Model.
Note
Slight naming differences exist between the
JavaScript and .NET versions of the object model. Rather than
explicitly state the various names for each object, I’ll use the .NET
names here. As a general rule, names in the JavaScript object model
begin with lowercase characters and properties are prefixed with get_.
Operation Batching
The ClientContext class includes a few methods that
are essential to the workings of the Client Object Model. The first of
these methods is the ClientContext.ExecuteQueryAsync method.
Earlier, in our architecture diagram, we saw that
the Client Object Model makes use of a WCF service as a proxy to
perform operations on the server. To reduce network load, what actually
happens is that all requests are queued by the ClientContext object and
are sent to the server only when the ExecuteQueryAsync method is
called. Conceptually, this is easy to understand, but it makes for some
interesting caveats when it comes to developing against the Client
Object Model.
To see how this works, consider our earlier Silverlight code sample:
private void Button_Click(object sender, RoutedEventArgs e)
{
ClientContext ctx=new ClientContext("Your Site URL Here");
Web web = ctx.Web;
ctx.Load(web);
ctx.ExecuteQueryAsync((s, args) =>
{
Dispatcher.BeginInvoke(() => {
label1.Content = "Title:" + web.Title +
", Description:" + web.Description; });
}, null);
}
In this snippet, we’re creating a ClientContext
object and then picking up a reference to its Web property. However,
before we can read the values of the web object, we need to call the
ClientContext.Load method to queue the object for loading and then call
ExecuteQueryAsync to execute the queued operations.
As its name suggests, ExecuteQueryAsync is
an asynchronous operation. It accepts as parameters two delegates: one
to be called if the operation fails and another to be called when the
operation is successful. For simplicity, we’ve used lambda expressions
in this sample. When writing code that uses the Silverlight Client
Object Model or the JavaScript Client Object Model, ExecuteQueryAsync
must be used to make an asynchronous call to Client.svc. However, if
using the Managed Client Object Model, which is generally the case when
integrating rich client applications, it’s possible to call Client.svc
synchronously by using the ClientContext.ExecuteQuery method.