Monday, May 28, 2012

Client Object model

http://msdn.microsoft.com/en-us/library/ee857094(office.14).aspx

The SharePoint 2010 Client Object Model is a very cool feature of SharePoint 2010 Foundation Server that enables developers to write applications that access SharePoint data from a .NET application running on a client computer, from a Silverlight application, and from JavaScript running client-side in a SharePoint web part.  The client object model enables this without requiring the developer to write or install code on the SharePoint server.  The client object model makes it possible to build new categories of applications that integrate with Microsoft SharePoint Foundation 2010, including writing .NET applications, rich interactive web parts, and Silverlight applications.
I've written an MSDN article, Using the SharePoint 2010 Managed Client Object Model, that provides the basics on using the Client Object Model.  Many thanks to Michael Cheng of the client object model team for technically reviewing the article, and providing me with many suggestions that improved it.
The article Using the SharePoint 2010 Client Object Model with the Open XML SDK 2.0 provides additional information around uploading and downloading files from a document library, as well as examples that modify Open XML documents using the Open XML SDK.

Using the SharePoint Foundation 2010 Managed Client Object Model

SharePoint 2010
19 out of 30 rated this helpful - Rate this topic
Published: November 2009
Summary:  Learn how to use the SharePoint Foundation 2010 managed client object model to write applications that are based on the .NET Framework and access SharePoint content from clients without installing code on the server that runs SharePoint Foundation 2010.
Applies to:  SharePoint Foundation 2010
Provided by:  Eric White, Microsoft Corporation
Contents

Overview

With the SharePoint Foundation 2010 managed client object model, you can design client applications that access SharePoint content without installing code on the server that runs Microsoft SharePoint Foundation 2010. For example, you can build new categories of applications that include writing applications that are based on the Microsoft .NET Framework, rich interactive Web Parts, Microsoft Silverlight applications, and ECMAScript (JavaScript, JScript) applications that run client-side in a SharePoint Web Part. For example:
  • A team leader creates a SharePoint site that has many lists that are required to manage her team’s mission. She wants to change these lists in an ad-hoc manner—perhaps updating assignments and estimates based on an Open XML spreadsheet, or moving items from one SharePoint list to another. She wants to write a small custom application to help her manage this.
  • A software company that sells a traditional rich client application wants to integrate SharePoint document libraries and lists into their application, and they want this integration to be seamless, or even invisible to their users.
  • A SharePoint developer wants to build a rich Web Part for a SharePoint deployment that brings list content into their custom AJAX web code. He also wants to build an even richer Silverlight application that does the same thing.
What do these people have in common? They can use the SharePoint Foundation 2010 managed client object model to achieve their goals. The SharePoint Foundation 2010 managed client object model lets you write client-side code to work with all the common objects in SharePoint sites. Through the object model, you can add and remove lists, add, update, and delete list items, change documents in document libraries, create sites, manage permissions of items, and add and remove Web Parts from a page.
Previously, there were few options. You could use Web services to interact with SharePoint lists and other features, but this was challenging. If the Web services did not provide the necessary capabilities, you could write server-side code to provide a new Web service (an even more difficult task). Some IT departments disallow server-side code, or allow only code that is written by the IT department so that sometimes that was not an option. The SharePoint Foundation 2010 managed client object model enables new kinds of applications and makes it easier to write client-side code that interacts with SharePoint content.

Using the SharePoint Foundation 2010 Managed Client Object Model

To use the SharePoint Foundation 2010 managed client object model (client object model), you write managed code based on the .NET Framework that uses an API that resembles the object model that is used on a server that is running SharePoint Foundation. The client object model has classes for accessing site collection information, site information, and list and list item information.
In the case of Web Parts, you use an ECMAScript (JavaScript, JScript) programming interface that resembles the .NET Framework API. For Silverlight, you use a subset of the API that is available through the .NET Framework on the client. Although much of the information that is presented in this article is relevant to the JavaScript and Silverlight APIs, this article focuses primarily about how to use the SharePoint Foundation 2010 managed client object model from a client application that is based on the .NET Framework.
The SharePoint Foundation 2010 managed client object model consists of two assemblies that contain five namespaces. If you look at the classes available in those namespaces, you see many classes. Do not worry; many of those classes are used internally by the object model. You are interested only in a subset of them, primarily classes that have direct counterparts to some familiar classes in the SharePoint Foundation server object model.

Table 1. Client-side classes and server-side equivalents

Client Server
ClientContext SPContext
Site SPSite
Web SPWeb
List SPList
ListItem SPListItem
Field SPField
Notice that the SharePoint Foundation 2010 managed client object model uses the same legacy naming pattern for site collections and sites as the server object model. The Site class represents site collections, and the Web class represents sites. My preference for using these classes is to name the variables so that the variable name indicates whether it is a site collection or a site, even though you must use the Site and Web classes to declare them.
The following example shows how I name variables.
ClientContext clientContext = new ClientContext(siteUrl);
Site siteCollection = clientContext.Site;
Web site = clientContext.Web;

How the Client-Side Object Model Works

An application that uses SharePoint content interacts with the API in several ways—call methods and get the return values, pass a Collaborative Application Markup Language (CAML) query and get the results, and set or get properties. After you use the API to perform a specific task the SharePoint Foundation 2010 managed client object model bundles up these uses of the API into XML and sends it to the server that runs SharePoint Foundation. The server receives this request, and makes appropriate calls into the object model on the server, collects the responses, forms them into JavaScript Object Notation (JSON), and sends that JSON back to the SharePoint Foundation 2010 managed client object model. The client object model parses the JSON and presents the results to the application as .NET Framework objects (or JavaScript objects for JavaScript). The following diagram shows these interactions.


Figure 1. The SharePoint Foundation 2010 managed client object model

0ebaeb17-ceb2-43a7-9ebe-22adc04b6137 It is important to be aware that you control when the SharePoint Foundation 2010 managed client object model starts to send the XML to the server and receives the JSON back from the server.
The bundling of multiple method calls into a single call to the server is dictated by the realities of network speed, network latency, and desired performance characteristics. If the SharePoint Foundation 2010 managed client object model interacted with the server at every method call, the performance of the system, and the increased network traffic would make the system unworkable.
As I mentioned, you explicitly control when the SharePoint Foundation 2010 managed client object model bundles method calls and sends a request to the server. As part of this process, before you start the interaction with the server, you must explicitly specify what content that you want to retrieve from the server. This is the biggest difference between the SharePoint Foundation 2010 managed client object model and the SharePoint Foundation 2010 object model. But after you understand the model, it is not challenging. The easiest way to start understanding the difference is to see a simple application.

Creating Windows Console Managed Client Object Model Applications

note Note:
I use Windows console applications for the sample code, but you can use the same approach with other application types.
To build the application, you must add references to two assemblies, Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll. Installing SharePoint Foundation installs these assemblies on the server. The two assemblies are located in the following directory:
%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI
Important Important:
For SharePoint Foundation Beta and Microsoft SharePoint Server 2010 Beta, you must copy the two assemblies and put them in a convenient location on your development client computer. You must browse to those assemblies to add references to them when you are setting up projects that use the SharePoint Foundation 2010 managed client object model.

To build the application

  1. Start Microsoft Visual Studio 2010.
  2. On the File menu, point to New, and then click Project.
  3. In the New Project dialog box, in the Recent Template pane, expand Visual C#, and then click Windows.
  4. To the right of the Recent Template pane, click Console Application.
  5. By default, Visual Studio creates a project that targets .NET Framework 4, but you must target .NET Framework 3.5. From the list at the upper part of the File Open dialog box, select .NET Framework 3.5.
  6. In the Name box, type the name that you want to use for your project, such as FirstClientApiApplication.
  7. In the Location box, type the location where you want to place the project.


    Figure 2. Creating a solution in the New Project dialog box

    6fff7a0d-bf31-4042-acb2-72a16fce6e19
  8. Click OK to create the solution.

To add references to the Microsoft.SharePoint.Client assembly and Microsoft.SharePoint.Client.Runtime assembly

  1. The classes that you use in a client object model application are located in Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll. As I mentioned, before you add the references, you must copy those assemblies from the server that runs SharePoint Foundation to the client development computer.
  2. On the Project menu, click Add Reference to open the Add Reference dialog box.
  3. Select the Browse tab, navigate to the location where you put the Microsoft.SharePoint.Client.dll and Microsoft.SharePoint.Client.Runtime.dll. Select both DLLs, and then click OK as shown in Figure 3.


    Figure 3. Adding references to the assemblies

    820cc11d-ae55-4acb-9cf5-8272117ce0df

To add the sample code to the solution

  1. In Visual Studio, replace the contents of the Program.cs source file with the following code.
    using System;
    using Microsoft.SharePoint.Client;
    
    class DisplayWebTitle
    {
        static void Main()
        {
            ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
            Web site = clientContext.Web;
            clientContext.Load(site);
            clientContext.ExecuteQuery();
            Console.WriteLine("Title: {0}", site.Title);
        }
    }
    
  2. Replace the URL in the ClientContext constructor with the URL to the SharePoint site. Build and run the solution. The example prints the title of the site.
Just as with the SharePoint Foundation server object model, you create a context for the SharePoint site that you want to access. You can then retrieve a reference to the site from the context.
The call to the ExecuteQuery method causes the SharePoint Foundation 2010 managed client object model to send the request to the server. There is no network traffic until the application calls the ExecuteQuery method.
An important point to make about this example is that the call to the Load method does not actually load anything. Instead, it informs the client object model that when the application calls the ExecuteQuery method, you want to load the property values of the siteCollection object.
This is the model that all interactions with the server take:
  1. You inform the SharePoint Foundation 2010 managed client object model about the operations that you want to take. This includes accessing the values of properties of objects (for example, objects of the List class, ListItem class, and Web class), CAML queries that you want to run, and objects such as ListItem objects that you want to insert, update or delete.
  2. Then you call the ExecuteQuery method. No network traffic occurs until you call the ExecuteQuery method. Until that point, your application is only registering its requests.
As you can see from this example, at its simplest, you first set up a query, and then you execute the queries. This causes the client object model to send traffic to the server and receive a response from it. This next section reviews the model in detail and shows why it is designed the way it is, and finally, how you can build applications by using the model.

Overview of the SharePoint Foundation 2010 Managed Client Object Model

There are specific aspects of the client object model that you must examine:
  • Approaches that the client object model takes to minimize network traffic
  • Query construction
  • Techniques to improve server performance
  • How to create, update, and delete client objects
  • How to work with very large lists
Before we delve into any of these subjects, let's examine the issue of object identity.

Using Object Identities

The key idea behind object identity is that client objects refer to the corresponding in the SharePoint Foundation server object model both before and after they call the ExecuteQuery method. They continue to refer to that same object through multiple calls to the ExecuteQuery method.
This means that when setting up the query, the client object model returns objects that you can use to further set up the query before you call the ExecuteQuery method. This lets you to write more complex queries before you start causing traffic to and from the server. You can do more interesting things in a single query, and eliminate network traffic.
The following example gets the Announcements list object, and then it retrieves all items of that list by using the simplest possible CAML query.
using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Announcements");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = "<View/>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(list);clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
            Console.WriteLine("Id: {0} Title: {1}", listItem.Id, oListItem["Title"]);
    }
}
Notice the sequence in this example:
  1. First the code gets a List object by using the GetByTitle method. Remember, this List object has no data in it; it does not have data in any of its properties until the application calls the ExecuteQuery method.
  2. It then calls the GetItems method on the list object, even though that list object is not populated with data.
  3. It finally calls the Load method on both the list object and listItems object, and then calls the ExecuteQuery method.
The key point about this is that the client object model remembers that the list object is the one that the application initialized by using the GetByTitle method, and that the client object model should execute the CAML query on that same list object after the list object is retrieved from the SharePoint database. Any class that derives from the ClientObject class has these semantics.
And, as mentioned, you can continue to use client objects to set up additional queries after you call the ExecuteQuery method. In the following example, the code loads the list object and calls the ExecuteQuery method. It then uses that list client object to call the List.GetItems method, and then calls the ExecuteQuery method again. The list object retained its identity through the call to ExecuteQuery method.
using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists
            .GetByTitle("Announcements");
        clientContext.Load(list);
        clientContext.ExecuteQuery();
        Console.WriteLine("List Title: {0}", list.Title);
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = "<View/>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(listItems);
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
            Console.WriteLine("Id: {0} Title: {1}",
                oListItem.Id, listItem["Title"]);
    }
}

Some properties and methods return objects or value types that do not derive from the ClientObject class. You benefit from using client object identity to access methods and properties only when those methods and properties return client objects or collections of them. For instance, some classes, such as the FieldUrlValue class and the FieldLookupValue class derive from the ClientValueObject class, and you cannot use properties that return those types until after the call to the ExecuteQuery method. Some properties return .NET Framework types such as string or integer, and you also cannot use properties or methods that return those until after the call to the ExecuteQuery method. Because you cannot use the values of any properties until those values are populated in the ExecuteQuery call, you cannot, for example, find an item in a list, and use the value of one of that item’s fields to select items in an additional query. If you try to use a property before it is populated by the ExecuteQuery method, the client object model throws a PropertyOrFieldNotInitializedException exception.
Caution Caution:
Client object identity is valid only for a single ClientContext object. If you initialize another ClientContext object to the same SharePoint site, you cannot use client objects from one client context with the other one.
A number of later examples in this article use object identity behavior.
note Note:
This example does not do any error handling. If the Announcements list does not exist, the client object model throws an exception in the call to the ExecuteQuery method. You should be prepared to catch exceptions when you write code that may fail if you ask for objects that may not exist.

Trimming Result Sets

SharePoint Foundation is often deployed in organizations with many thousands of users. When building an application that accesses SharePoint Foundation over the network, it makes sense to build it so that it uses the least amount of network traffic. There are several ways that the client object model helps you do this. The simplest approach is to use lambda expressions to specify exactly which properties the client object model should return to the application.
The following example shows how to specify that when the client object model loads the site object, it must load only the Title property and Description property. This reduces the size of the JSON response from the server back to the client.
using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        Web site = clientContext.Web;
        clientContext.Load(site,
            s => s.Title,
            s => s.Description);
        clientContext.ExecuteQuery();
        Console.WriteLine("Title: {0} Description: {1}",
            site.Title, site.Description);
    }
}

By default, if you do not include these lambda expressions in the call to the Load method, it loads a much larger number of properties (but not them all). The first two examples called the Load method without specifying which properties to load, so that the JSON packet that the server returned was somewhat larger than it needed to be. Although in these small examples, it does not make much difference, when it loads thousands of list items, carefully specifying the required properties reduces network traffic.
Using lambda expressions, you can specify a list of properties to the Load method. Reducing network traffic is not the only benefit you derive from the client object model’s use of lambda expressions. Later on this article describes how to filter result sets using lambda expressions.
Next, I’ll show an example that creates a list and then add some content to it. This will provide sample content to work with for the rest of this article.

Creating and Populating a List

The following example creates a list, and adds some fields and several items to it.
using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        Web site = clientContext.Web;

        // Create a list.
        ListCreationInformation listCreationInfo =
            new ListCreationInformation();
        listCreationInfo.Title = "Client API Test List";
        listCreationInfo.TemplateType = (int)ListTemplateType.GenericList;
        List list = site.Lists.Add(listCreationInfo);

        // Add fields to the list.
        Field field1 = list.Fields.AddFieldAsXml(
            @"<Field Type='Choice'
                     DisplayName='Category'
                     Format='Dropdown'>
                <Default>Specification</Default>
                <CHOICES>
                  <CHOICE>Specification</CHOICE>
                  <CHOICE>Development</CHOICE>
                  <CHOICE>Test</CHOICE>
                  <CHOICE>Documentation</CHOICE>
                </CHOICES>
              </Field>",
            true, AddFieldOptions.DefaultValue);
        Field field2 = list.Fields.AddFieldAsXml(
            @"<Field Type='Number'
                     DisplayName='Estimate'/>",
            true, AddFieldOptions.DefaultValue);

        // Add some data.
        ListItemCreationInformation itemCreateInfo =
            new ListItemCreationInformation();
        ListItem listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Write specs for user interface.";
        listItem["Category"] = "Specification";
        listItem["Estimate"] = "20";
        listItem.Update();

        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Develop proof-of-concept.";
        listItem["Category"] = "Development";
        listItem["Estimate"] = "42";
        listItem.Update();
        
        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Write test plan for user interface.";
        listItem["Category"] = "Test";
        listItem["Estimate"] = "16";
        listItem.Update();

        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Validate SharePoint interaction.";
        listItem["Category"] = "Test";
        listItem["Estimate"] = "18";
        listItem.Update();

        listItem = list.AddItem(itemCreateInfo);
        listItem["Title"] = "Develop user interface.";
        listItem["Category"] = "Development";
        listItem["Estimate"] = "18";
        listItem.Update();

        clientContext.ExecuteQuery();
    }
}
In many cases, where you can create a client object, the application can call an Add method that takes as an argument an object that specifies creation information. This example shows how to use ListCreationInformation class to create a List object, and how to use the ListItemCreationInformation class for creating a ListItem object. You often set properties of the creation information class after instantiating it. You can see that the code sets the Title property and TemplateType property of the ListItemCreationInformation object. Note that to create a list, you call the Add method, but to create a ListItem object, you call the AddItem method. The Add method creates a list in the collection, and the AddItem method creates a single list item.
Creating fields in a list also does not use an Add method, because, when you create fields, you are not really creating an instance of the Field class. You are creating an instance of a class that derives from the Field class. There are many options available for those derived classes, and using an Add method would significantly complicate the design of a FieldCreationInformation class. For this reason, the client object model does not include such a class. Instead, the simplest way to create a field is to specify a bit of XML that defines the field, and pass that XML to the AddFieldAsXml method. There is a Add method that you can use to create a field, but instead of taking a FieldCreationInformation object, it takes another Field object as a parameter that it uses as a prototype for the field to be created. This is useful in some scenarios.
Tip Tip:
The Discovering the Schema for Fields section of this article shows you an easy way to discover the XML that you must specify for fields that you want to create.
Note that, of course, no objects are actually added to the SharePoint database until the application calls the ExecuteQuery method.
There is one more item of interest in this example. Notice that after you call the AddItem method, the example sets three indexed properties. The code is setting the values of the fields that were previously added to the list. After setting these properties, the application must call the Update method, informing the client object model that those objects were modified. The client object model does not work correctly if you do not do so. You see the Update method used in later examples, when I show how to modify existing client objects.
Now that you have some data, let us discover some interesting ways to query and change it.

Using CAML to Query Lists

The following example shows how to use CAML to query the list that you created in the last example. This example prints the Development items from our test list.
using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Client API Test List");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='Category'/>
                      <Value Type='Text'>Development</Value>
                    </Eq>
                  </Where>
                </Query>
                <RowLimit>100</RowLimit>
              </View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items
                 .Include(
                     item => item["Title"],
                     item => item["Category"],
                     item => item["Estimate"]));
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
        {
            Console.WriteLine("Title: {0}", listItem["Title"]);
            Console.WriteLine("Category: {0}", listItem["Category"]);
            Console.WriteLine("Estimate: {0}", listItem["Estimate"]);
            Console.WriteLine();
        }
    }
}
This example produces the following output.
Title: Develop proof-of-concept.
Category: Development
Estimate: 42

Title: Develop user interface.
Category: Development
Estimate: 18


You may notice a difference between the lambda expressions that you specify in this example and the lambda expressions in the example that is presented in the Trimming Result Sets section. You must use the Include extension method to specify the properties that you want to load for each item in the collection that we load. The items parameter of the lambda expression is of type ListItemCollection, which of course does not contain an indexed property that allows us to specify which properties to load for items in the collection. Instead, you call the Include extension method, which enables us to specify which parameters of that child collection to load. Parameters to lambda expressions in the Include extension method are of the type of the items of the collection. Therefore, you can specify the properties that you want to load for each item in the collection.
Again, it is not completely necessary to understand the exact semantics of this use of lambda expressions. Just remember two coding idioms:
If you are requesting that the client object model load certain properties of a client object (not a collection of them), then specify the properties in the lambda expression that you add directly in the Load method.
clientContext.Load(site,
    s => s.Title,
    s => s.Description);
If you are requesting that the client object model load certain properties of each item in a collection of client objects, use the Include extension method, and pass the lambda expressions that specify your desired properties to the Include method.
clientContext.Load(
    listItems,
    items => items.Include(
        item => item["Title"],
        item => item["Category"],
        item => item["Estimate"]));

Filtering the Child Collection Returned by Load by Using LINQ

Because the Include extension method returns IQueryable<T>, you can chain from the Include method into the IQueryable<T>.Where extension method. This provides a succinct way to filter the result set. You should only use this capability when querying client object collections other than collections of ListItem objects, because while you could use this technique to filter collections of ListItem objects, using CAML results in better performance. This is important enough to say again:
Caution Caution:
Never use the IQueryable<T>.Where extension method when querying ListItem objects. The reason is that the client object model first evaluates the result of the CAML query, retrieves the results, and then filters the resulting collection using LINQ. If you filter a very large list using LINQ instead of CAML, the client object model attempts to retrieve all items in the list before filtering with LINQ and either issues queries that require too much system resources, or the query fails. The reason is not clear unless you know how the client object model works internally. You must use CAML when querying list items.
The following example queries the client object model for all lists that are not hidden. Notice that you must include a using directive for the System.Linq namespace.
using System;
using System.Linq;
using Microsoft.SharePoint.Client;
 
class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        ListCollection listCollection = clientContext.Web.Lists;
        clientContext.Load(
            listCollection,
            lists => lists
                .Include(
                    list => list.Title,
                    list => list.Hidden)
                . Where(list => ! list.Hidden)
             );
        clientContext.ExecuteQuery();
        foreach (var list in listCollection)
            Console.WriteLine(list.Title);
    }
}
On my server, this example produces the following output.
Announcements
Calendar
Client API Test List
Content and Structure Reports
Customized Reports
Eric's ToDo List
Eric's Wiki
Form Templates
Links
Reusable Content
Shared Documents
Site Assets
Site Collection Documents
Site Collection Images
Site Pages
Style Library
Tasks
Team Discussion
Workflow Tasks

Using the LoadQuery Method

The LoadQuery method is similar in functionality to the Load method, except that in certain circumstances, the client object model can process the queries more efficiently and use memory more efficiently. It also allows for a more flexible programming style.
The LoadQuery method has different semantics than the Load method. Whereas the Load method populates the client object (or client object collection) with data from the server, the LoadQuery method populates and returns a new collection. This means that you can query the same object collection multiple times and keep separate result sets for each query. For instance, you can query for all items in a project list that are assigned to a certain person, and separately query for all items that have an estimated hours that is larger than a certain threshold, and access both result sets at the same time. It also enables you to let these collections go out of scope, and thereby become eligible for garbage collection. Collections that you load using the Load method are eligible for garbage collection only when the client context variable itself goes out of scope. Other than these differences, the LoadQuery method provides the same functionality as the Load method.
The following example uses the LoadQuery method to retrieve a list of all the lists in the site.
using System;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        Web site = clientContext.Web;
        ListCollection lists = site.Lists;
        IEnumerable<List> newListCollection = clientContext.LoadQuery(
            lists.Include(
                list => list.Title,
                list => list.Id,
                list => list.Hidden));
        clientContext.ExecuteQuery();
        foreach (List list in newListCollection)
            Console.WriteLine("Title: {0} Id: {1}",
                list.Title.PadRight(40), list.Id.ToString("D"));
    }
}
Notice that the LoadQuery method returns a new list collection that you can iterate through. The new list collection has a type of IEnumerable<List> instead of ListCollection.
There is one aspect of the semantics of the LoadQuery method that you must pay attention to. In the previous example, the original lists variable does not have its property values populated after the ExecuteQuery method returns. If you want that list to be populated, you must explicitly call the Load method, specifying which properties that you want loaded.

Increasing Performance by Nesting Include Statements in LoadQuery

When calling the LoadQuery method, you can specify multiple levels of properties to load. This allows the client object model to optimize its access to the server that runs SharePoint Foundation by reducing the number of times the client object model must call to the server that runs SharePoint Foundation to retrieve the data that you want. The following query retrieves all lists from the site, and all fields from each list. It then prints them to the console and indicates if each list or field is hidden.
using System;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        IEnumerable<List> lists = clientContext.LoadQuery(
            clientContext.Web.Lists.Include(
                list => list.Title,
                list => list.Hidden,
                list => list.Fields.Include(
                    field => field.Title,
                    field => field.Hidden)));
        clientContext.ExecuteQuery();
        foreach (List list in lists)
        {
            Console.WriteLine("{0}List: {1}",
                list.Hidden ? "Hidden " : "", list.Title);
            foreach (Field field in list.Fields)
                Console.WriteLine("  {0}Field: {1}",
                    field.Hidden ? "Hidden " : "",
                    field.Title);
        }
    }
}
This approach allows the server part of the client object model to be more efficient than if the application first loaded a list of lists, and then loaded fields for each list.

Filtering the Child Collection Returned by LoadQuery by Using LINQ

The LoadQuery method takes an object of type IQueryable<T> as its parameter, and this enables you to write LINQ queries instead of CAML to filter the results. This example returns a collection of all document libraries that are not hidden.
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;
 
class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        ListCollection listCollection = clientContext.Web.Lists;
        IEnumerable<List> hiddenLists = clientContext.LoadQuery(
            listCollection
                . Where(list => !list.Hidden &&
                      list.BaseType == BaseType.DocumentLibrary));
        clientContext.ExecuteQuery();
        foreach (var list in hiddenLists)
            Console.WriteLine(list.Title);
    }
}


Updating Client Objects

Updating client objects by using the client object model is fairly simple. You retrieve the objects, alter properties, call the Update method for each object that you change, and then call the ExecuteQuery method. The following example modifies items in the Client API Test List, increasing the estimate for all development items by 50 percent (a common operation).
using System;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Client API Test List");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='Category'/>
                      <Value Type='Text'>Development</Value>
                    </Eq>
                  </Where>
                </Query>
                <RowLimit>100</RowLimit>
              </View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items.Include(
                 item => item["Category"],
                 item => item["Estimate"]));
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems)
        {
            listItem["Estimate"] = (double)listItem["Estimate"] * 1.5;
            listItem.Update();
        }
        clientContext.ExecuteQuery();
    }
}

Deleting Client Objects

Deleting client objects is just as easy. However, there is one very important dynamic around deleting client objects from a client object collection. You cannot iterate through the collection, deleting objects. As soon as you delete the first object, it causes the iterator of the client object collection to malfunction. The iterator may throw an exception, or it may quietly finish but not visit all items in the collection. Instead, you must materialize the collection into a List<T> using the ToList method, and then iterate through that list, deleting the client objects.
The following example deletes the test items from our Client API Test List. It shows using the ToList method to materialize the collection before you iterate through it:
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext = new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists.GetByTitle("Client API Test List");
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml =
            @"<View>
                <Query>
                  <Where>
                    <Eq>
                      <FieldRef Name='Category'/>
                      <Value Type='Text'>Test</Value>
                    </Eq>
                  </Where>
                </Query>
                <RowLimit>100</RowLimit>
              </View>";
        ListItemCollection listItems = list.GetItems(camlQuery);
        clientContext.Load(
             listItems,
             items => items.Include(
                 item => item["Title"]));
        clientContext.ExecuteQuery();
        foreach (ListItem listItem in listItems.ToList())
            listItem.DeleteObject();
        clientContext.ExecuteQuery();
    }
}

The following code example shows the incorrect approach.
clientContext.Load(
    listItems,
    items => items.Include(
        item => item["Title"]));
clientContext.ExecuteQuery();

// The ToList() method call is removed in the following line.
foreach (ListItem listItem in listItems)  
    listItem.DeleteObject();

clientContext.ExecuteQuery();

Finally, to clean up the Client API Test List, here is an example that deletes the list and its items.
using System;
using Microsoft.SharePoint.Client;

class DisplayWebTitle
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        clientContext.Web.Lists.GetByTitle("Client API Test List")
            .DeleteObject();
        clientContext.ExecuteQuery();
    }
}

Discovering the Schema for Fields

As promised, this section shows an easy way to discover the XML schema that you use to create the fields that you want to create in a list. First, on the SharePoint site, create a list that contains columns that are configured as you want them. Then you can then use the following example to output the XML that creates those fields.
The following example prints the field schemas for the fields that I added to the Client API Test List.
using System;
using System.Linq;
using System.Xml.Linq;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        List list = clientContext.Web.Lists
            .GetByTitle("Client API Test List");
        clientContext.Load(list);
        FieldCollection fields = list.Fields;
        clientContext.Load(fields);
        clientContext.ExecuteQuery();
        foreach (var f in fields)
        {
            XElement e = XElement.Parse(f.SchemaXml);
            string name = (string)e.Attribute("Name");
            if (name == "Category" || name == "Estimate")
            {
                e.Attributes("ID").Remove();
                e.Attributes("SourceID").Remove();
                e.Attributes("ColName").Remove();
                e.Attributes("RowOrdinal").Remove();
                e.Attributes("StaticName").Remove();
                Console.WriteLine(e);
                Console.WriteLine("===============");
            }
        }
    }
}
When you run this after you create the list by using the example program in the section Creating and Populating a List, it produces the following output.
<Field Type="Choice" DisplayName="Category" Format="Dropdown" Name="Category">
  <Default>Specification</Default>
  <CHOICES>
    <CHOICE>Specification</CHOICE>
    <CHOICE>Development</CHOICE>
    <CHOICE>Test</CHOICE>
    <CHOICE>Documentation</CHOICE>
  </CHOICES>
</Field>
===============
<Field Type="Number" DisplayName="Estimate" Name="Estimate" />
===============

The example removes attributes that are not required for creating the field.

Accessing Large Lists

SharePoint development guidelines indicate that you should not attempt to retrieve more than 2000 items in a single query. If this is a possibility in your application, consider using the RowLimit element in your CAML queries to limit how much data that the client object model retrieves for your application. Sometimes you must access all items in a list that may contain more than 2000 items. If you must do so, then best practice is to page through the items 2000 at a time. This section presents an approach to paging using the ListItemCollectionPosition property.
using System;
using System.Linq;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main()
    {
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");

        List list = clientContext.Web.Lists
            .GetByTitle("Client API Test List");

        // First, add 20 items to Client API Test List so that there are
        // enough records to show paging.
        ListItemCreationInformation itemCreateInfo =
            new ListItemCreationInformation();
        for (int i = 0; i < 20; i++)
        {
            ListItem listItem = list.AddItem(itemCreateInfo);
            listItem["Title"] = String.Format("New Item #{0}", i);
            listItem["Category"] = "Development";
            listItem["Estimate"] = i;
            listItem.Update();
        }
        clientContext.ExecuteQuery();

        // This example shows paging through the list ten items at a time.
        // In a real-world scenario, you would want to limit a page to
        // 2000 items.
        ListItemCollectionPosition itemPosition = null;
        while (true)
        {
            CamlQuery camlQuery = new CamlQuery();
            camlQuery.ListItemCollectionPosition = itemPosition;
            camlQuery.ViewXml =
                @"<View>
                    <ViewFields>
                      <FieldRef Name='Title'/>
                      <FieldRef Name='Category'/>
                      <FieldRef Name='Estimate'/>
                    </ViewFields>
                    <RowLimit>10</RowLimit>
                  </View>";
            ListItemCollection listItems = list.GetItems(camlQuery);
            clientContext.Load(listItems);
            clientContext.ExecuteQuery();
            itemPosition = listItems.ListItemCollectionPosition;
            foreach (ListItem listItem in listItems)
                Console.WriteLine("  Item Title: {0}", listItem["Title"]);
            if (itemPosition == null)
                break;
            Console.WriteLine(itemPosition.PagingInfo);
            Console.WriteLine();
        }
    }
}
This example produces the following output:
  Item Title: Write specs for user interface.
  Item Title: Develop proof-of-concept.
  Item Title: Write test plan for user interface.
  Item Title: Validate SharePoint interaction.
  Item Title: Develop user interface.
  Item Title: New Item #0
  Item Title: New Item #1
  Item Title: New Item #2
  Item Title: New Item #3
  Item Title: New Item #4
Paged=TRUE&p_ID=10

  Item Title: New Item #5
  Item Title: New Item #6
  Item Title: New Item #7
  Item Title: New Item #8
  Item Title: New Item #9
  Item Title: New Item #10
  Item Title: New Item #11
  Item Title: New Item #12
  Item Title: New Item #13
  Item Title: New Item #14
Paged=TRUE&p_ID=20

  Item Title: New Item #15
  Item Title: New Item #16
  Item Title: New Item #17
  Item Title: New Item #18
  Item Title: New Item #19


Asynchronous Processing

If you are building an application that must attach to SharePoint sites that may not be available, or if you must regularly invoke queries that may take a long time, you should consider using asynchronous processing. This enables your application to continue to be responsive to your user while the query executes in a separate thread. In your main thread, you can set a timer to let you know if the query is taking longer than your desired threshold, you can keep the user posted with the status of the query, and when the query finally finishes, you can display the results.
The JavaScript version of the client object model and the Silverlight version (when it modifies the user interface) use asynchronous processing. The topic Data Retrieval Overview in the SharePoint 2010 SDK contains examples of how to use asynchronous processing using JavaScript and Silverlight.
When building a traditional application that is based on the .NET Framework, such as a Windows Forms or WPF application, you may want to use asynchronous processing. The following example uses the BeginInvoke method to execute a query asynchronously. Notice that the code passes a statement lambda expression to the BeginInvoke method, which makes it convenient to create this pattern, because the statement lambda expression can refer to automatic variables in the method that contains it. You can see that the statement lambda expression has access to the clientContext variable and the newListCollection variable. Microsoft Visual C# closures make the language function as you expect.
using System;
using System.Collections.Generic;
using Microsoft.SharePoint.Client;

class Program
{
    static void Main(string[] args)
    {
        AsynchronousAccess asynchronousAccess = new AsynchronousAccess();
        asynchronousAccess.Run();
        Console.WriteLine("Before exiting Main");
        Console.WriteLine();
        Console.WriteLine("In a real application, the application can");
        Console.WriteLine("continue to be responsive to the user.");
        Console.WriteLine();
        Console.ReadKey();
    }
}

class AsynchronousAccess
{
    delegate void AsynchronousDelegate();

    public void Run()
    {
        Console.WriteLine("About to start a query that will take a long time.");
        Console.WriteLine();
        ClientContext clientContext =
            new ClientContext("http://intranet.contoso.com");
        ListCollection lists = clientContext.Web.Lists;
        IEnumerable<List> newListCollection = clientContext.LoadQuery(
            lists.Include(
                list => list.Title));
        AsynchronousDelegate executeQueryAsynchronously =
            new AsynchronousDelegate(clientContext.ExecuteQuery);
        executeQueryAsynchronously.BeginInvoke(
            arg =>
            {
                clientContext.ExecuteQuery();
                Console.WriteLine("Long running query completed.");
                foreach (List list in newListCollection)
                    Console.WriteLine("Title: {0}", list.Title);
            }, null);
    }
}
The example produces the following output.
About to start a query that will take a long time.

Before exiting Main

In a real application, the application can
continue to be responsive to the user.

Long running query completed.
Title: Announcements
Title: Cache Profiles
Title: Calendar
Title: Client API Test List
Title: Content and Structure Reports
Title: Content type publishing error log
Title: Converted Forms
Title: Customized Reports
Title: Eric's ToDo List
Title: Eric's Wiki
Title: Form Templates
Title: Links

 

 

 

SharePoint 2010 - Complete details about Client Object Model

This is the introduction to the Client Object model introduced in the SharePoint 2010. This is going to be a huge help and useful part in SharePoint 2010 for developers and makes lot of customization to the existing SharePoint system.

In eariler versions, I mean till SharePoint 2007 the code runs using the SharePoint object model to run against the server which is running SharePoint. Other than the SharePoint server object model, other way is, simply reference the web service and use that to get and manipulate data. Then what is the need of SharePoint 2010 Client object model[Cleint OM] concept?

What is Client Object Model?
Client Object Model is introduced in SharePoint 2010 which helps to developers to make things easier to develop the client side applications for SharePoint 2010. Client Object Model can run on the client machines (Where SharePoint is not installed) and communicate with the SharePoint server remotely. This is the great advantage for the SharePoint devs as they don't have to install SharePoint for development any more.

What are the different Client OM supporting in the SharePoint 2010 API? [Client API]
  1. .NET Managed Client - Implemented in .NET CLR. I mean we use this in Web, Windows and Console applications.
  2. Silverlight Client - You can use the SharePoint objects in Silver light coding. Wow, this is going to be a huge advantage to  the Silverlight applications which can be integrated into SharePoint. Before we don't have access to SharePoint objects inside Silverlight context.
  3. ECMAScript Client - Through javascript too, we can get context and do manipulations to SharePoint objects. Do you think it's possible? Yes, its a brilliant way of thinking from Microsoft SharePoint team and this will help in great scenarios. Will explain later in this article.
Why Client Object Model comes into the picture? Are there any specialties of them?
The main started point to think by SharePoint team are as follows.
  1. Is it really necessary to have SharePoint installed on server for SharePoint development? - Yes, in SharePoint 2007 you have to install SharePoint on the server to write code and test it.
  2. What is the advantage of writing more web services to serve what the clients are looking for? - This is completely not a feasible solution to give or expose web services for each and every single requirement to get and manipulate data. It has plenty of limitations and if Microsoft exposes 500 web services and you didn't find what you really need and they are just waste. Instead write whatever you want and use them.
  3. The great thinking and beautiful solution to the people who don't allow server side coding in the SharePoint sites is ECMAscript client OM. You can create a simple javascript file and deploy into the server to get what you needed. As we know, most of the clients don't allow server side coding but they want something to be developed. In SharePoint 2007 it's very difficult to get this job done. But now in SP 2010 very easy.
So, these things take into high priority and makes them to come up with a great solution in the form of Client Object Model. The great advantage of it is completely looks [Syntax] like the SharePoint Object Model. So, nothing new for developers and no confusion. Infact very simple to manage and write code.

SharePoint object model syntax:
Server side syntaxClient side syntax
SPContextClientContext
SPSiteSite
SPWebWeb
SPListList
Now, I believe you have understood the Client OM concept. Now, we will discuss a little bit about technical implementation.
SharePoint 2010 provides the client support files to refer the SharePoint objects and communicate with the SharePoint server. Below are the details.
For Managed ClientDLL's needed : Microsoft.SharePoint.Client.dll, Microsoft.SharePoint.Client.Runtime.dll. Find these files in the 14/ISAPI folder. Usually, the location would be at "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI".
SilverlightMicrosoft.SharePoint.Client.Silverlight.dll and Microsoft.SharePoint.Client.Silverlight.Runtime.dll. They find at "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin".
ECMAScriptSP.js file - The file fund at "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS".

What we need to do is, add the relted file to the project references if it is Managed client or Silverlight and start using the SharePoint objects in the code. If it is ECMAScript then we just need to declare the line     ExecuteOrDelayUntilScriptLoaded(Initialize, "sp.js"); on the top of js file to use the SP object.
**Initialize is some javascript function.**
My next posts will be the examples of each client OM implementation and how to get, manipulate data for better understanding.





Working With SharePoint Data ‎(8)

The purpose of this section is how to use sharepoint foundation web application from client object model.
Querying from Client-side Code : We have four ways to query to sharepoint foundation server
1. Querying from the clint object model.
2. querying from REST web service that implement ADO.Net data service framework.
3. Querying from inbuilt web services such as list web service, webs  web service etc.
4. Querying by using owssver.dll assembly
Querying from client object model:- 2 ways to query with client object model.
1. Implement CAML Query with the CAML Query class
2. Query any sharepoint foundation object that implement I<enumerable> with Linq based query.

Using the ADO.NET Data Services Framework

If your client application does not use new client object model and you only need to query on the list data. you can always use ado.net service framework to query on content database by using ADO.net data service framework.

Avoid Using SharePoint Data-Providing Web Services

Avoid Making Direct Calls to owssvr.dll

Using the SharePoint Foundation Client APIs


SharePoint 2010 Client Object Model – The new client-side object model provides remote access to the functionality of the SharePoint Foundation server-side object model. In previous releases of SharePoint Foundation, SOAP web services provided access to only a fraction of the server-side object model, but in SharePoint Foundation 2010, the client object model fills many of the gaps.
ASP.NET Web Services – The legacy web services provide remote access to a SharePoint Foundation deployment through SOAP web services.
SharePoint Foundation REST Interface – The new SharePoint Foundation REST interface exposes lists and libraries as a relational data service, and serves as a standards-based interface for interoperability with other platforms.
WCF Services in SharePoint Foundation 2010 – If the combination of the other client APIs is not sufficient, extend SharePoint Foundation with your own custom web service. By default SharePoint Foundation 2010 supports creating not only custom ASP.NET web services, as in previous releases, but also custom WCF web services.
Walkthrough: Creating and Implementing a Custom WCF Service in SharePoint Foundation – This walkthrough shows how to create a WCF service that uses the server-side object model, and a Windows Forms Application that implements the service and that uses the new client-side object model and REST interface.

SharePoint 2010 Client Object Model

This section of the Microsoft SharePoint 2010 Software Development Kit (SDK) introduces three new client APIs that allow you to interact with SharePoint sites from script that executes in the browser, from code (no earlier than Microsoft .NET Framework 3.5) that executes in a .NET mana
ged application, or from code that executes in a Microsoft Silverlight 2.0 application. The new ECMAScript (JavaScript, JScript), .NET managed, and Silverlight client object models each provide a subset of the server object model that is defined in Microsoft.SharePoint.dll,

SharePoint 2010 Client Object Model Hierarchy and Identity

Microsoft SharePoint Foundation 2010 has three object models for working on the client-side. These are the managed .NET object model, the managed Silverlight object model, and the unmanaged ECMAScript (JavaScript, JScript) object model.


You should be aware of the following important differences between the ECMAScript (JavaScript, JScript) and managed client object models.
  • The method signature may be different, as with the ClientContext() constructor (JavaScript: ClientContext(serverRelativeUrl)). In JavaScript this constructor takes a server-relative URL, but the managed version of this constructor takes either a full URL or a Uri.
  • The two object models use different data value types. The JavaScript object model does not have equivalents for all the data value types in the .NET Framework managed object model. JavaScript regards StringCollection as string[]. On the other hand, JavaScript has some values that the .NET Framework does not have, such as NaN, or negative and positive infinity.
  • The JavaScript object model allows Forms authentication, but you cannot specify the authentication mechanism to connect to the server. For information about the managed client object models and Forms authentication, see Authentication in the Managed Client Object Models.
  • When you are creating an item and adding it to an existing collection, further updates cannot be performed with that collection while the query is outstanding. This issue pertains to adding an item to a collection; otherwise, multiple clients can simultaneously read and write to existing items within a collection.
  • As part of general security, you cannot use the JavaScript object model on a page to work with Microsoft SharePoint Foundation 2010 data unless the page contains a form digest control, for example, <SharePoint:FormDigest runat="server"/>.
  • You generally cannot share variables across scopes, so for this reason you cannot use common coding patterns for try/catch/finally statements.
  • A RoleDefinitionBindingCollection object used in creating role assignments does not have object identity. Therefore, if you create a new RoleDefinitionBindingCollection object and then try to use it after creating a role assignment, an error is returned.
  • Some case-insensitive comparisons do not work the same way on the client as they do on the server. Some server-side comparisons use the Web site locale to do a comparison, but the client can only use invariant culture to avoid frequent round trips.  SharePoint Foundation 2010 does not support case-insensitive comparisons if the server is using a Web site locale.
  • Due to the limitations of an asynchronous postback, you may find that inline script is not called when the page is in certain modes, for example, when a Wiki page is in edit mode. In this case, use a ScriptManager control and its RegisterStartupScript() method to register a startup script block for executing your code, instead of using inline script.


Server.NET Managed and SilverlightJavaScript
Microsoft.SharePoint.SPContext Microsoft.SharePoint.Client.ClientContext SP.ClientContext
Microsoft.SharePoint.SPSite Microsoft.SharePoint.Client.Site SP.Site
Microsoft.SharePoint.SPWeb Microsoft.SharePoint.Client.Web SP.Web
Microsoft.SharePoint.SPList Microsoft.SharePoint.Client.List SP.List
Microsoft.SharePoint.SPListItem Microsoft.SharePoint.Client.ListItem SP.ListItem
Microsoft.SharePoint.SPField (including major derived classes)Microsoft.SharePoint.Client.Field SP.Field
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager Microsoft.SharePoint.Client.WebParts.LimitedWebPartManager SP.WebParts.LimitedW

Server.NET Managed and SilverlightJavaScript
Microsoft.SharePoint.SPContext Microsoft.SharePoint.Client.ClientContext SP.ClientContext
Microsoft.SharePoint.SPSite Microsoft.SharePoint.Client.Site SP.Site
Microsoft.SharePoint.SPWeb Microsoft.SharePoint.Client.Web SP.Web
Microsoft.SharePoint.SPList Microsoft.SharePoint.Client.List SP.List
Microsoft.SharePoint.SPListItem Microsoft.SharePoint.Client.ListItem SP.ListItem
Microsoft.SharePoint.SPField (including major derived classes)Microsoft.SharePoint.Client.Field SP.Field
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager Microsoft.SharePoint.Client.WebParts.LimitedWebPartManager SP.WebParts.LimitedW


Server.NET Managed and SilverlightJavaScript
Microsoft.SharePoint.SPContext Microsoft.SharePoint.Client.ClientContext SP.ClientContext
Microsoft.SharePoint.SPSite Microsoft.SharePoint.Client.Site SP.Site
Microsoft.SharePoint.SPWeb Microsoft.SharePoint.Client.Web SP.Web
Microsoft.SharePoint.SPList Microsoft.SharePoint.Client.List SP.List
Microsoft.SharePoint.SPListItem Microsoft.SharePoint.Client.ListItem SP.ListItem
Microsoft.SharePoint.SPField (including major derived classes)Microsoft.SharePoint.Client.Field SP.Field
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager Microsoft.SharePoint.Client.WebParts.LimitedWebPartManager SP.WebParts.LimitedW


Server.NET Managed and SilverlightJavaScript
Microsoft.SharePoint.SPContext Microsoft.SharePoint.Client.ClientContext SP.ClientContext
Microsoft.SharePoint.SPSite Microsoft.SharePoint.Client.Site SP.Site
Microsoft.SharePoint.SPWeb Microsoft.SharePoint.Client.Web SP.Web
Microsoft.SharePoint.SPList Microsoft.SharePoint.Client.List SP.List
Microsoft.SharePoint.SPListItem Microsoft.SharePoint.Client.ListItem SP.ListItem
Microsoft.SharePoint.SPField (including major derived classes)Microsoft.SharePoint.Client.Field SP.Field
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager Microsoft.SharePoint.Client.WebParts.LimitedWebPartManager SP.WebParts.LimitedW

Access list data by using the Server object model

Tuesday, May 15, 2012

Docflow Timer Job for Document Synch..

Purpose: The purpose of this timer job to update the status of deliverable of Docflow from the GDMS systems in timely fashion. On a particuler time it takes synch the docflow document status from the GDMS System.

Code flow and functionality..
override

There are two functions defined in the basic functionality one for documentSynch and other for DocumentContribution synch.. Document synch pull all the items from the Docflow Calender list except Completed and Discontinued, takes the releated document from the Document list and update the status. while documentcontribution picks the records from the Docuemnt list.

using the web application we picks site and using the site we pick web.
objSPListItemCollection is the collection of items from Docflow calender except Completed and Discontinued.

SynchronizeDocument(currentSPweb, objSPListItemCollection);

Loop through each item of objSPLIstItemCollection check the intiationstart of calender item if it is null then assign to new DateTime(1900,1,1) otherwise pick from calender list item and put the calender status to the local variable status.
actualInitStartDate =

//now get the document list item heredocListItem =
The common function used to get the document of the particuler calenderlist item in which we pass the calenderListItemID.
DocumentDAO.GetDocumentListItemByCalendarID(currentSPweb.Site.Url, CalenderListItem.ID.ToString());
The DocListItem is getting from Document List using the SPQuery Object.

If DocList item is not null then we pull the following fields values to access the data from GDMS.
 Convert.ToString(docListItem[GlobalConstants.COLUMN_GDMS_R_OBJECT_ID]);Convert.ToString(docListItem[GlobalConstants.COLUMN_GDMS_I_CHRONICLE_ID]);
strObjectID =
strChronicleID =

In StrNewObjectID it gets the versionID to communicate from the GDMS web service passing the crediantials using the cryptography format. first getting the applicable versionID to communicate from GDMS web service and passing this to the GDMS database and apply the query to find this chronicleID.. if it find then assign it to the strNewObjectID.
string

Now apply the function, If strObjectID not equel to strNewObjectID apply function
if
{

}

In the above function only two fields are updating one is  gdms_r_object_id and other is GDMS_x0020_Link

//now get GDMS document object based on object idobjGDMSObject =

Now Check If objGDMSObject is not equal to null  then

If  the status of objGDMSObject is "In Review" then set the
// set the list item status to review
then set the status of following fields
CalenderListItem[
updatedStatus =
CalenderListItem[
iscalendarChange =
GlobalConstants.COLUMN_DOCFLOW_STATUS] = Enumerators.DocStatus.Review.ToString();Enumerators.DocStatus.Review.ToString();GlobalConstants.COLUMN_ACTUAL_APPROVAL_START_DATE] = null;true;
GDMSDataBaseDAO.GETDGMSObject(currentSPweb.Site.Url, strNewObjectID);
(strObjectID != strNewObjectID)CalendarDAO.UpdateDocumentObjectInfo(docListItem, strNewObjectID);
queryNewObject = "select r_object_id from pfe_document where i_chronicle_id = '" + strChronicleID + "';";
void Execute funtion : 

and setting the start date from the //set the start date from audit trail event

//if status = pending approval
update the status
//always update latest the Approval start date from audit trail event
// set earliest review start date

else
|| objGDMSObject.Status.Equals(
|| objGDMSObject.Status.Equals(
|| objGDMSObject.Status.Equals(

Updating followings fields
CalenderListItem[
CalenderListItem[
CalenderListItem[
CalenderListItem[


If GDMS status is unknown else condition
CalenderListItem[
updatedStatus =
CalenderListItem[
iscalendarChange =

{
dtReviewStartDate =

{
CalenderListItem[
}
GlobalConstants.COLUMN_DOCFLOW_STATUS] = Enumerators.DocStatus.Review.ToString();Enumerators.DocStatus.Review.ToString();GlobalConstants.COLUMN_ACTUAL_APPROVAL_START_DATE] = null;true;if (String.IsNullOrEmpty(Convert.ToString(CalenderListItem[GlobalConstants.COLUMN_ACTUAL_REVIEW_START_DATE])))GDMSDataBaseDAO.GetObjectReviewStartDate(currentSPweb.Site.Url, objGDMSObject, actualInitStartDate);if (dtReviewStartDate.HasValue)GlobalConstants.COLUMN_ACTUAL_REVIEW_START_DATE] = dtReviewStartDate;
GlobalConstants.COLUMN_ACTUAL_REVIEW_START_DATE]
GlobalConstants.COLUMN_ACTUAL_APPROVAL_START_DATE]
GlobalConstants.COLUMN_ACTUAL_RAD_HANDOVER_DATE]
GlobalConstants.COLUMN_DOCFLOW_STATUS]
if (objGDMSObject.Status.Equals(GlobalConstants.GDMS_DOC_STATUS_FIT_FOR_USE)GlobalConstants.GDMS_DOC_STATUS_APPROVED)GlobalConstants.GDMS_DOC_STATUS_FINAL)GlobalConstants.GDMS_DOC_STATUS_EFFECTIVE))



SynchronizeRelatedDocumentContributions(SPWeb oWeb)

Retrieving allitems from the Document List, Converting to datatable if collection is not empty. creating query to making a call in database to all the list items
strQuery =

Removing all the items from "Document Contributions" List. using the for loop.
Looping through the each item of Document List, retrieving row to the datarow object and retrieving the
gdms_r_object_id and checking whether it has value or not, If it has
//now get GDMS document object based on object id
// get a string concating all related document ids
// constructing query to get related document info
// assume the list is empty,

Checking the condition of
GDMS_DOC_STATUS_FINAL
GDMS_DOC_STATUS_HA_APPROVED
GDMS_DOC_STATUS_APPROVED
GDMS_DOC_STATUS_EFFECTIVE and inseting the fields accordingly.
// foreach related document returned, create an entry in document contribution list
"select r_object_id, r_version_label,xm_status,title ,subtype, pfe_xm_p_lc_change,i_chronicle_id from gtc_document(all) where r_object_id in


Timer job logs has been logged on the
LIST_Logs, Logs list.


How to create TimerJob
1. Create a class inherited from SPJobDefinition create constructor and override the Execute method write your logic in Execute method.
  GDMSContributionSync : SPJobDefinition{
// No Argument Constructor (required for the system internal operation)
{
}

:
{
}
public
{}

2. Create the feature that should have a reciever class in which you configure the Job, where you add the job on the portal and configure it for schedule.

// GDMSDocumentSync Job

GDMSDocumentSync objTimerJob = new GDMSDocumentSync(GlobalConstants.FEATURE_GDMS_DOCUMENT_SYNC, currentSite.WebApplication);SPDailySchedule schedule = new SPDailySchedule();//this service will start at 1 AMschedule.BeginHour = 2;
schedule.BeginMinute = 2;
schedule.EndHour = 3;
objTimerJob.Schedule = schedule;
objTimerJob.Title =
currentSite.WebApplication.JobDefinitions.Add(objTimerJob);
objTimerJob.Update();

3. Activate a feature, If you can develope a screen to schedule the job to run.


objContSyncTimerJob.Title = jobName;
objContSyncTimerJob.Schedule = schedule;
objContSyncTimerJob.IsDisabled = rdbLstJobStatus.Items[1].Selected;
objContSyncTimerJob.Update();
case GlobalConstants.FEATURE_GDMS_CONTRIBUTION_SYNC:GDMSContributionSync objContSyncTimerJob = new GDMSContributionSync(GlobalConstants.FEATURE_GDMS_CONTRIBUTION_SYNC, currentSite.WebApplication);

4. You can debug the timer job from OWStimer process.
GlobalConstants.FEATURE_GDMS_DOCUMENT_SYNC;
override void Execute(Guid targetInstanceId)
public GDMSContributionSync()public GDMSContributionSync(string JobName, SPWebApplication objWebApplication)base(JobName, objWebApplication, null, SPJobLockType.Job)
class

Wednesday, May 2, 2012

Best Practice while developing shareoint solutions

Best Practices: Common Coding Issues When Using the SharePoint Object Model

Windows SharePoint Services 3
66 out of 98 rated this helpful - Rate this topic
Summary: Learn common issues encountered by developers who write custom code by using the SharePoint object model. (15 printed pages)
Scott Harris, Microsoft Corporation
Mike Ammerlaan, Microsoft Corporation
Steve Peschka, Microsoft Corporation
Roger Lamb, Microsoft Corporation
Published: September 2007
Updated: July 2010
Applies to: Windows SharePoint Services 3.0, Windows SharePoint Services 2.0, Microsoft Office SharePoint Server 2007
Contents

Overview

Developers who write custom code with the SharePoint object model will encounter common issues related to performance, extensibility, and scalability. This article is a resource for developers who are working to troubleshoot and improve the performance of existing SharePoint applications or who are writing new SharePoint applications. In both cases, it is important to understand how to make the SharePoint object model work efficiently, and how to apply general programming techniques (such as caching and threading) to the SharePoint platform specifically. This information can make it easier to design your applications correctly, find and fix problem areas in your code, and avoid known pitfalls of using the SharePoint object model.
The following areas reflect the most common general concerns encountered by SharePoint developers:
  • Using SharePoint data and objects efficiently
  • Performance concerns related to folders, lists, and SPQuery objects
  • Writing applications that scale to large numbers of users
  • Using Web controls and timer jobs
  • Disposing of SharePoint objects
This article addresses all but the last of these issues. For guidance on disposing of SharePoint objects, see Best Practices: Using Disposable Windows SharePoint Services Objects.
Additionally, we recommend that you read the following orientation topics as good starting points for using the SharePoint object model:

Using SharePoint Data and Objects Efficiently

Caching is one good way to improve system performance. However, you must weigh the benefits of caching against the need for thread safety. Additionally, you should not create certain SharePoint objects within event receivers because this will cause performance problems related to excessive database calls.
This section describes these common areas of concern so that you can learn ways to optimize your use of SharePoint objects and data.

Caching Data and Objects

Many developers use the Microsoft .NET Framework caching objects (for example, System.Web.Caching.Cache) to help take better advantage of memory and increase overall system performance. But many objects are not "thread safe" and caching those objects can cause applications to fail and unexpected or unrelated user errors.
Bb687949.note(en-us,office.12).gifNote:
The caching techniques discussed in this section are not the same as the custom caching options for Web content management that are discussed in Custom Caching Overview.

Caching SharePoint Objects That Are Not Thread Safe

You might try to increase performance and memory usage by caching SPListItemCollection objects that are returned from queries. In general, this is a good practice; however, the SPListItemCollection object contains an embedded SPWeb object that is not thread safe and should not be cached.
For example, assume the SPListItemCollection object is cached in a thread. As other threads try to read this object, the application can fail or behave strangely because the embedded SPWeb object is not thread safe. For more information about the SPWeb object and thread safety, see the Microsoft.SharePoint.SPWeb class.
The guidance in the following section describes how you can prevent multiple threads from attempting to read the same cached object.

Understanding the Potential Pitfalls of Thread Synchronization

You might not be aware that your code is running in a multithreaded environment (by default, Internet Information Services, or IIS, is multithreaded) or how to manage that environment. The following example shows the code some developers use to cache Microsoft.SharePoint.SPListItemCollection objects.
Bad Coding Practice
Caching an Object That Multiple Threads Might Read
public void CacheData()
{
   SPListItemCollection oListItems;

   oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
   if(oListItems == null)
   {
      oListItems = DoQueryToReturnItems();
      Cache.Add("ListItemCacheName", oListItems, ..);
   }
}
Although the use of the cache in this example is functionally correct, because the ASP.NET cache object is thread safe, it introduces potential performance problems. (For more information about ASP.NET caching, see the Cache class.) If the query in the preceding example takes 10 seconds to complete, many users could try to access that page simultaneously during that amount of time. In this case, all of the users would run the same query, which would attempt to update the same cache object. If that same query runs 10, 50, or 100 times, with multiple threads trying to update the same object at the same time—especially on multiprocess, hyperthreaded computers—performance problems would become especially severe.
To prevent multiple queries from accessing the same objects simultaneously, you must change the code as follows.
Applying a Lock
Checking for null
private static object _lock =  new object();

public void CacheData()
{
   SPListItemCollection oListItems;

   lock(_lock) 
   {
      oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
      if(oListItems == null)
      {
         oListItems = DoQueryToReturnItems();
         Cache.Add("ListItemCacheName", oListItems, ..);
     }
   }
}
You can increase performance slightly by placing the lock inside the if(oListItems == null) code block. When you do this, you do not need to suspend all threads while checking to see if the data is already cached. Depending on the time it takes the query to return the data, it is still possible that more than one user might be running the query at the same time. This is especially true if you are running on multiprocessor computers. Remember that the more processors that are running and the longer the query takes to run, the more likely putting the lock in the if() code block will cause problems. If you want to make absolutely sure that another thread has not created oListItems before the current thread has a chance to work on it, you could use the following pattern.
Applying a Lock
Rechecking for null
private static object _lock =  new object();

public void CacheData()
{
   SPListItemCollection oListItems;
       oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
      if(oListItems == null)
      {
         lock (_lock) 
         {
              //Ensure that the data was not loaded by a concurrent thread while waiting for lock.
              oListItems = (SPListItemCollection)Cache[“ListItemCacheName”];
              if (oListItems == null)
              {
                   oListItems = DoQueryToReturnItems();
                   Cache.Add("ListItemCacheName", oListItems, ..);
              }
         }
     }
}

If the cache is already populated, this last example performs as well as the initial implementation. If the cache is not populated and the system is under a light load, acquiring the lock will cause a slight performance penalty. This approach should significantly improve performance when the system is under a heavy load, because the query will be executed only once instead of multiple times, and queries are usually expensive in comparison with the cost of synchronization.
The code in these examples suspends all other threads in a critical section running in IIS, and prevents other threads from accessing the cached object until it is completely built. This addresses the thread synchronization issue; however, the code is still not correct because it is caching an object that is not thread safe.
To address thread safety, you can cache a DataTable object that is created from the SPListItemCollection object. You would modify the previous example as follows so that your code gets the data from the DataTable object.
Good Coding Practice
Caching a DataTable Object
private static object _lock =  new object();

public void CacheData()
{
   DataTable oDataTable;
   SPListItemCollection oListItems;
   lock(_lock)
   {
           oDataTable = (DataTable)Cache["ListItemCacheName"];
           if(oDataTable == null)
           {
              oListItems = DoQueryToReturnItems();
              oDataTable = oListItems.GetDataTable();
              Cache.Add("ListItemCacheName", oDataTable, ..);
           }
   }
}
For more information and examples of using the DataTable object, and other good ideas for developing SharePoint applications, see the reference topic for the DataTable class.

Using Objects in Event Receivers

Do not instantiate SPWeb, SPSite, SPList, or SPListItem objects within an event receiver. Event receivers that instantiate SPSite, SPWeb, SPList, or SPListItem objects instead of using the instances passed via the event properties can cause the following problems:
  • They incur significant additional roundtrips to the database. (One write operation can result in up to five additional roundtrips in each event receiver.)
  • Calling the Update method on these instances can cause subsequent Update calls in other registered event receivers to fail.
Bad Coding Practice
Instantiating an SPSite Object Inside an Event Receiver
public override void ItemDeleting(SPItemEventProperties properties)
{
    using (SPSite site = new SPSite(properties.WebUrl))

    using (SPWeb web = site.OpenWeb())
        {
        SPList list = web.Lists[properties.ListId];
        SPListItem item = list.GetItemByUniqueId(properties.ListItemId);
        // Operate on item.
        }
    }
}

Good Coding Practice
Using SPItemEventProperties
// Retrieve SPWeb and SPListItem from SPItemEventProperties instead of
// from a new instance of SPSite.
SPWeb web = properties.OpenWeb();
// Operate on SPWeb object.
SPListItem item = properties.ListItem;
// Operate on item.
If you do not apply this fix in your code, when you call Update on the new instance, you must invalidate it with the Invalidate method in the appropriate child class of SPEventPropertiesBase (for example, SPItemEventProperties.InvalidateListItem or SPItemEventProperties.InvalidateWeb).

Working with Folders and Lists

When folders and lists grow in size, custom code that works with them needs to be designed in ways that optimize performance. Otherwise, your applications will run slowly and even cause timeouts to occur. The following recommendations for addressing performance concerns while working with large folders and lists are based on the test results reported in Steve Peschka's white paper, Working with Large Lists in Office SharePoint Server 2007.
  1. Do not use SPList.Items.

    SPList.Items selects all items from all subfolders, including all fields in the list. Use the following alternatives for each use case.

    • Retrieving all items in a list

      Use SPList.GetItems(SPQuery query) instead. Apply filters, if appropriate, and specify only the fields you need to make the query more efficient. If the list contains more than 2,000 items, you will need to paginate the list in increments of no more than 2,000 items. The following code example shows how to paginate a large list.

      Good Coding Practice

      Retrieving Items with SPList.GetItems

      SPQuery query = new SPQuery();
      SPListItemCollection spListItems ; 
      string lastItemIdOnPage = null; // Page position.
      int itemCount = 2000
       
      while (itemCount == 2000)
      {
          // Include only the fields you will use.
          query.ViewFields = "<FieldRef Name=\"ID\"/><FieldRef Name=\"ContentTypeId\"/>";   
          query.RowLimit = 2000; // Only select the top 2000.
          // Include items in subfolder (if necessary).
          query.ViewAttributes = "Scope=\"Recursive\"";
          StringBuilder sb = new StringBuilder();
          // To make it order by ID and stop scanning the table, specify the OrderBy override attribute.
          sb.Append("<OrderBy Override=\"TRUE\"><FieldRef Name=\"ID\"/></OrderBy>");
          //.. Append more text as necessary ..
          query.Query = sb.ToString();
          // Get 2,000 more items.
       
          SPListItemCollectionPosition pos = new SPListItemCollectionPosition(lastItemIdOnPage);
          query.ListItemCollectionPosition = pos; //page info
          spListItems = spList.GetItems(query);
          lastItemIdOnPage = spListItems.ListItemCollectionPosition.PagingInfo;
          // Code to enumerate the spListItems.
          // If itemCount <2000, we finish the enumeration.
          itemCount = spListItems.Count;
      
      }
      
      
      The following example shows how to enumerate and paginate a large list.

      SPWeb oWebsite = SPContext.Current.Web;
      SPList oList = oWebsite.Lists["Announcements"];
      
      SPQuery oQuery = new SPQuery();
      oQuery.RowLimit = 10;
      int intIndex = 1;
      
      do
      {
          Response.Write("<BR>Page: " + intIndex + "<BR>");
          SPListItemCollection collListItems = oList.GetItems(oQuery);
      
          foreach (SPListItem oListItem in collListItems)
          {
              Response.Write(SPEncode.HtmlEncode(oListItem["Title"].ToString()) +"<BR>");
          }
      
          oQuery.ListItemCollectionPosition = collListItems.ListItemCollectionPosition;
          intIndex++;
      } while (oQuery.ListItemCollectionPosition != null);
      
      
    • Getting items by identifier

      Instead of using SPList.Items.GetItemById, use SPList.GetItemById(int id, string field1, params string[] fields). Specify the item identifier and the field that you want.
  2. Do not enumerate entire SPList.Items collections or SPFolder.Files collections.

    Accessing the methods and properties that are listed in the left column of the following table will enumerate the entire SPList.Items collection, and cause poor performance and throttling for large lists. Instead, use the alternatives listed in the right column.

    Table 1. Alternatives to SPList.Items

    Poor Performing Methods and Properties Better Performing Alternatives
    SPList.Items.Count SPList.ItemCount
    SPList.Items.XmlDataSchema Create an SPQuery object to retrieve only the items you want.
    SPList.Items.NumberOfFields Create an SPQuery object (specifying the ViewFields) to retrieve only the items you want.
    SPList.Items[System.Guid] SPList.GetItemByUniqueId(System.Guid)
    SPList.Items[System.Int32] SPList.GetItemById(System.Int32)
    SPList.Items.GetItemById(System.Int32) SPList.GetItemById(System.Int32)
    SPList.Items.ReorderItems(System.Boolean[],System.Int32[],System.Int32) Perform a paged query by using SPQuery and reorder the items within each page.
    SPFolder.Files.Count SPFolder.ItemCount
    Bb687949.note(en-us,office.12).gifNote:
    The SPList.ItemCount property is the recommended way to retrieve the number of items in a list. As a side effect of tuning this property for performance, however, the property can occasionally return unexpected results. If the precise number is required, you should use the poorer performing GetItems(SPQuery query), as shown in the preceding code example.
  3. Use PortalSiteMapProvider (Microsoft Office SharePoint Server 2007 only).

    Steve Peschka's white paper Working with Large Lists in Office SharePoint Server 2007 describes an efficient approach to retrieving list data in Office SharePoint Server 2007 by using the PortalSiteMapProvider class. PortalSiteMapProvider provides an automatic caching infrastructure for retrieving list data. The GetCachedListItemsByQuery method of PortalSiteMapProvider takes an SPQuery object as a parameter, and then checks its cache to determine whether the items already exist. If they do, the method returns the cached results. If not, it queries the list and stores the results in a cache. This approach works especially well when you are retrieving list data that does not change significantly over time. When data sets change frequently, the class incurs the performance cost of continually writing to the cache in addition to the costs of reading from the database. Consider that the PortalSiteMapProvider class uses the site collection object cache to store data. This cache has a default size of 100 MB. You can increase the size of this cache for each site collection on the object cache settings page for the site collection. But this memory is taken from the shared memory available to the application pool and can therefore affect the performance of other applications. Another significant limitation is that you cannot use the PortalSiteMapProvider class in applications based on Windows Forms. The following code example shows how to use this method.

    Good Coding Practice

    Using PortalSiteMap Provider

    // Get the current SPWeb object. 
    SPWeb curWeb = SPControl.GetContextWeb(HttpContext.Current); 
    
    // Create the query. 
    SPQuery curQry = new SPQuery(); 
    curQry.Query = "<Where><Eq><FieldRef Name='Expense_x0020_Category'/>
    <Value Type='Text'>Hotel</Value></Eq></Where>"; 
    
    // Create an instance of PortalSiteMapProvider. 
    PortalSiteMapProvider ps = PortalSiteMapProvider.WebSiteMapProvider; 
    PortalWebSiteMapNode pNode = ps.FindSiteMapNode(curWeb.ServerRelativeUrl) as PortalWebSiteMapNode; 
    
    // Retrieve the items. 
    
    SiteMapNodeCollection pItems = ps.GetCachedListItemsByQuery(pNode, "myListName_NotID", curQry, curWeb); 
    
    // Enumerate through all of the matches. 
    foreach (PortalListItemSiteMapNode pItem in pItems)
       { 
       // Do something with each match.
       }
    
    
  4. Whenever possible, acquire a reference to a list by using the list's GUID or URL as a key.

    You can retrieve an SPList object from the SPWeb.Lists property by using the list's GUID or display name as an indexer. Using SPWeb.Lists[GUID] and SPWeb.GetList(strURL) is always preferable to using SPWeb.Lists[strDisplayName]. Using the GUID is preferable because it is unique, permanent, and requires only a single database lookup. The display name indexer retrieves the names of all the lists in the site and then does a string comparison with them. If you have a list URL instead of a GUID, you can use the GetList method to look up the list's GUID in the content database before retrieving the list.

Deleting Multiple Versions of a List Item

When you delete multiple versions of a list item, use the DeleteByID method; do not use the Delete method. You will experience performance problems if you delete each SPListItemVersion object from an SPListItemVersionCollection object. The recommended practice is to create an array that contains the ID properties of each version and then delete each version by using the SPFileVersionCollection.DeleteByID method. The following code examples demonstrate both the approach that is not recommended and the recommended approach to deleting all versions of the first item of a custom list.
Bad Coding Practice
Deleting each SPListItemVersion object
SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];
SPListItem item = list.GetItemById(1); 
SPListItemVersionCollection vCollection = item.Versions;
ArrayList idList = new ArrayList();
foreach(SPListItemVersion ver in vCollection)
{
  idList.Add(ver.VersionId);
}
foreach(int verID in idList)
{
  SPListItemVersion version = vCollection.GetVersionFromID(verID); 
try
{
  version.Delete();
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);  
}
}
Good Coding Practice
Deleting each version of a list item by using the SPFileVersionCollection.DeleteByID method
SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];
SPListItem item = list.GetItemById(1);
SPFile file = web.GetFile(item.Url);
SPFileVersionCollection collection = file.Versions;
ArrayList idList = new ArrayList();
foreach (SPFileVersion ver in collection)
{
  idList.Add(ver.ID);
}
foreach (int verID in idList)
{
try
{
  collection.DeleteByID(verID);
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);  
}
}
If you are deleting versions of items in a document library, you can use a similar approach by retrieving the SPListItem.File.Versions property, as in the following code example.
Good Coding Practice
Deleting each version of a list item in a document library by using the SPFileVersionCollection.DeleteByID method
SPSite site = new SPSite("site url");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["custom list name"];
SPFile file = list.RootFolder.Files[0];
SPFileVersionCollection collection = file.Versions;

ArrayList idList = new ArrayList();
foreach (SPFileVersion ver in collection)
{
  idList.Add(ver.ID);
}
foreach (int verID in idList)
{
try
{
  collection.DeleteByID(verID);
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);  
}
}

Writing Applications That Scale to Large Numbers of Users

You might not be aware that you need to write your code to be scalable so that it can handle multiple users simultaneously. A good example is creating custom navigation information for all sites and subsites on each page or as part of a master page. If you have a SharePoint site on a corporate intranet and each department has its own site with many subsites, your code might resemble the following.
public void GetNavigationInfoForAllSitesAndWebs()
{
   foreach(SPSite oSPSite in SPContext.Current.Site.WebApplication.Sites)
   {
      try
      {
         SPWeb oSPWeb  = oSPSite.RootWeb;
         AddAllWebs(oSPWeb );
      }
      finally
      {
         oSPSite.Dispose();
      }
   }
}
public void AddAllWebs(SPWeb oSPWeb)
{
   foreach(SPWeb oSubWeb in oSPWeb.Webs)
   {
       try
       {
           //.. Code to add items ..
           AddAllWebs(oSubWeb);
       }
       finally
       {
            if (oSubWeb != null)
            oSubWeb.Dispose();
       }
   }
}
While the previous code disposes of objects properly, it still causes problems because the code iterates through the same lists over and over. For example, if you have 10 site collections and an average of 20 sites or subsites per site collection, you would iterate through the same code 200 times. For a small number of users this might not cause bad performance. But, as you add more users to the system, the problem gets worse, as shown in Table 2.

Table 2. Iterations increase as number of users increases

Users Iterations
102000
5010000
100200000
250500000
Although the code executes for each user that hits the system, the data remains the same for each user. The impact of this can vary depending on what the code is doing. In some cases, repeating code might not cause a performance problem; however, in the previous example the system must create a COM object (SPSite or SPWeb objects are created when retrieved from their collections), retrieve data from the object, and then dispose of the object for each item in the collection. This can have a significant impact on performance.
How to make this code more scalable or fine-tune it for a multiple user environment can be a hard question to answer. It depends on what the application is designed to do.
You should take the following into consideration when asking how to make code more scalable:
  • Is the data static (seldom changes), somewhat static (changes occasionally), or dynamic (changes constantly)?
  • Is the data the same for all users, or does it change? For example, does it change depending on the user who is logged on, the part of the site being accessed, or the time of year (seasonal information)?
  • Is the data easily accessible or does it require a long time to return the data? For example, is it returning from a long-running database query or from remote databases that can have some network latency in the data transfers?
  • Is the data public or does it require a higher level of security?
  • What is the size of the data?
  • Is the SharePoint site on a single server or on a server farm?
How you answer the previous questions will determine in which of several ways you can make your code more scalable and handle multiple users. The intent of this article is not to provide answers for all of the questions or scenarios but to provide a few ideas that you can apply to your specific needs. The following sections offer areas for your consideration.

Caching Raw Data

You can cache your data by using the System.Web.Caching.Cache object. This object requires that you query the data one time and store it in the cache for access by other users.
If your data is static, you can set up the cache to load the data only one time and not expire until the application is restarted, or to load the data once per day to ensure data freshness. You can create the cache item when the application starts, when the first user session starts, or when the first user tries to access that data.
If your data is somewhat static, you can set up the cached items to expire within a certain number of seconds, minutes, or hours after the data is created. This enables you to refresh your data within a timeframe that is acceptable to your users. Even if the data is cached for only 30 seconds, under heavy loads you will still see improved performance because you are running the code only one time every 30 seconds instead of multiple times per second for each user who hits the system.
Security trimming is another issue to consider whenever you cache data. For example, if you cache items as you iterate through a list, you may get only a subset of the data (the data that the current user can see), or if you use a DataTable object to cache all of the items in a list, you have no easy way of applying security trimming to users who belong to groups that can see only a subset of the data. For more information about storing security trimmed data in caches, see the CrossListQueryCache class.
In addition, ensure you consider the issues described earlier in Caching Data and Objects.

Building Data Before Displaying It

Think about how your cached data will be used. If this data is used to make run-time decisions, putting it into a DataSet or DataTable object might be the best way to store it. You can then query those objects for the data to make run-time decisions. If the data is being used to display a list, table, or formatted page to the user, consider building a display object and storing that object in the cache. At run time, you need only retrieve the object from the cache and call its render function to display its contents. You could also store the rendered output; however, this can lead to security issues and the cached item could be quite large, causing increased page swapping or memory fragmentation.

Caching For a Single Server or Server Farm

Depending on how you set up your SharePoint site, you might have to address certain caching issues differently. If your data must be the same on all servers at all times, then you must ensure that the same data is cached on each server.
One way to ensure this is to create the cached data and store it on a common server or in a Microsoft SQL Server database. Again, you must consider how much time it takes to access the data and what security issues can arise from storing the data on a common server.
You can also create business-layer objects that cache data on a common sever, and then access that data by using various interprocess communications that are available in networking objects or APIs.

Using SPQuery Objects

SPQuery objects can cause performance problems whenever they return large result sets. The following suggestions will help you optimize your code so that performance will not suffer greatly whenever your searches return large numbers of items.
  • Do not use an unbounded SPQuery object.

    An SPQuery object without a value for RowLimit will perform poorly and fail on large lists. Specify a RowLimit between 1 and 2000 and, if necessary, page through the list.
  • Use indexed fields.

    If you query on a field that is not indexed, the query will be blocked whenever it would result in a scan of more items than the query threshold (as soon as there are more items in the list than are specified in the query threshold). Set SPQuery.RowLimit to a value that is less than the query threshold.
  • If you know the URL of your list item and want to query by FileRef, use SPWeb.GetListItem(string strUrl, string field1, params string[] fields) instead.

Using Web Controls

When you inherit and override controls in the Microsoft.SharePoint.WebControls namespace, remember that SharePoint Web controls are templated controls. Unlike Microsoft ASP.NET Web controls, they are defined and rendered with templates instead of with the CreateChildControls method. Instead of having a thick CreateChildControls method that uses the new operator to create child controls, perform most child control creation and rendering by using the rendering templates that are referenced in the Template, AlternateTemplate, DisplayTemplate, CustomTemplate, and AlternateCustomTemplate properties of the SharePoint Web control. SharePoint Web controls do inherit the CreateChildControls method, but that method should typically do little or nothing beyond calling the parent control's CreateChildControls method and perhaps a bit of "final polish" rendering, such as assigning default values to child control properties in New mode or assigning the current values in Edit mode.
For an example, see Walkthrough: Creating a Custom Field Type. In addition, see the Microsoft.SharePoint.WebControls namespace.

Creating Timer Jobs

Design your timer jobs so that they consist of small, manageable pieces. Because administrators and other events, such as system restarts, can stop timer jobs, you can minimize the amount of rework after any interruption by breaking timer jobs into small pieces of work.

Conclusion

To ensure that your SharePoint system performs at its best, you need to be able to answer the following questions about the code you write:
  • Does my code properly dispose of SharePoint objects?
  • Does my code cache objects properly?
  • Does my code cache the correct types of objects?
  • Does my code use thread synchronization when necessary?
  • Does my code work as efficiently for 1,000 users as it does for 10 users?
If you consider these issues when you write your code, your SharePoint system will run more efficiently and your users will have a much better experience. You can also help to prevent unexpected failures and errors in your system.

Acknowledgements

We would like to acknowledge the following persons for their tremendous help in technical reviews for this article: James Waymire (Microsoft Corporation), Duray Akar (Microsoft Corporation), Rashid Aga (Microsoft Corporation), Roger Lamb (Microsoft Corporation), and Jeff Lin (Microsoft Corporation).

Additional Resources


  1. Don't cache SharePoint objects that are not Thread Safe
Let's take real time scenario, we have to bind dropdown list with the SharePoint list. We know SharePoint list which we are binding with dropdown list is not going to change frequently, so caching will be better option to improve the performance of the application. Sample code is mentioned below:
                      SPListItemCollection colItems;
            if(null != HttpRuntime.Cache[key])
            {
                ddlItems = (SPListItemCollection)HttpRuntime.Cache[key];
            }
            else
            {
                // Do query on sharepoint listand cach SPListItemCollection object
            }
But we are unaware that SPListItemCollection object contains an embedded SPWeb object that is not thread safe and should not be cached.

Good Coding Practice is to cache DataTable in place of SPListItemCollection object.
Sample Code:
         private static object _lock =  new object();

         private DataTable GetDropDownItems()
         {
         DataTable dtDropDownItems;

   SPListItemCollection objListItems;
   lock(_lock)
   {
             dtDropDownItems= (DataTable)Cache["CachedDropDownItems"];
           if(dtDropDownItems== null)
           {
              objListItems = //Do query onSharePoint List
              dtDropDownItems= objListItems.GetDataTable();
              Cache.Add("CachedDropDownItems ", dtDropDownItems,..); // provide rest of the parameter of this method
           }
   }
   }

Note: There are various methods to cache object like HttpRuntime, System.Web.Caching.Cache,  and HttpContext.Current.Cache. Choose one to the method to cache depending upon your application requirement.

    2. Retrieve or fetch SPList instance from SPWeb object: There might be the multiple approach to get the instance of SPList in SharePoint. But while developing an application we should keep in mind about performance of the application. Mentioned below are two approach to achieve the same.

        Approach 1: Not Recommended
        SPList objSpList = <SPWeb>.Lists["<List Title>"];  

        Approach 2: Recommended
        SPList objSpList = <SPWeb>.GetList("<List URL>");
   
        In the first approach, SharePoint loads "metadata" of all the SharePoint lists of current SPWeb object and then create SPList instance by Title comparison and also if Title of SharePoint list gets changed, There will be a code change. But in the second approach, SharePoint fetches GUID of the SharePoint list by list url and then loads the "metadata" of that particular list. User can not update the list URL after SharePoint list creation. So there is no possibility of any code change in this approach.

    3. JavaScript methods call on page load in SharePoint: Sometime we need to call JavaScript methods on page to change UI or to set some controls value. we can use window.onload event to achieve this functionality. But I personally recommend that to use "_spBodyOnLoadFunctionNames" method provided by SharePoint because sometimes window.onload don't work properly.
        Approach 1: Not Recommended
        window.onload = funcation(){//JavaScript code};
        window.onload = <JavaScript method name>;

        Approach 2: Recommended
        _spBodyOnLoadFunctionNames.push('<JavaScript method name>');

     4. Set RowLimit, ViewFields, and ViewFiledsOnly properties while fetching data from SharePoint list:
         Let take me take an example to make understand importance of these properties.
      Scenario: Suppose there isa list to store employee details. Following fields are present in this list:
<!--[if !supportLists]-->·    Name
<!--[if !supportLists]-->·    Designation
<!--[if !supportLists]-->·    Domain
<!--[if !supportLists]-->·    Address
<!--[if !supportLists]-->·    Email
<!--[if !supportLists]-->·    Contact Number
<!--[if !supportLists]-->·    Rating
      We have to create a webpart to show top 5 employees name, designation and email in the home page of site based on employee rating.