Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010

**Resumen:**aprenda a usar el modelo de objetos de cliente administrado de SharePoint Foundation 2010 para escribir aplicaciones basadas en .NET Framework y obtener acceso a contenido de SharePoint desde clientes sin instalar código en el servidor que ejecuta SharePoint Foundation 2010.

Última modificación: lunes, 09 de marzo de 2015

Hace referencia a: Business Connectivity Services | Office 2010 | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

En este artículo
Información general
Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010
Funcionamiento del modelo de objetos del lado cliente
Creación de aplicaciones de modelo de objetos de cliente administrado de consola de Windows
Información general del modelo de objetos de cliente administrado de SharePoint Foundation 2010
Uso de identidades de objeto
Recorte de conjuntos de resultados
Creación y rellenado de una lista
Uso de CAML para consultar listas
Filtrado de la colección de elementos secundarios devuelta por Load mediante LINQ
Uso del método LoadQuery
Aumento del rendimiento mediante el anidamiento de instrucciones Include en LoadQuery
Filtrado de la colección de elementos secundarios devuelta por LoadQuery mediante LINQ
Actualización de objetos de cliente
Eliminación de objetos de cliente
Detección del esquema de los campos
Acceso a listas grandes
Procesamiento asincrónico
Recursos adicionales

Se aplica a:  SharePoint Foundation 2010

Proporcionado por:  Eric White, Microsoft Corporation

Contenido

  • Información general

  • Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010

  • Funcionamiento del modelo de objetos del lado cliente

  • Creación de aplicaciones de modelo de objetos de cliente administrado de consola de Windows

  • Información general del modelo de objetos de cliente administrado de SharePoint Foundation 2010

  • Uso de identidades de objeto

  • Recorte de conjuntos de resultados

  • Creación y rellenado de una lista

  • Uso de CAML para consultar listas

  • Filtrado de la colección de elementos secundarios devuelta por Load mediante LINQ

  • Uso del método LoadQuery

  • Aumento del rendimiento mediante el anidamiento de instrucciones Include en LoadQuery

  • Filtrado de la colección de elementos secundarios devuelta por LoadQuery mediante LINQ

  • Actualización de objetos de cliente

  • Eliminación de objetos de cliente

  • Detección del esquema de los campos

  • Acceso a listas grandes

  • Procesamiento asincrónico

  • Recursos adicionales

Información general

Con el modelo de objetos de cliente administrado de SharePoint Foundation 2010, se pueden diseñar aplicaciones cliente que pueden obtener acceso a contenido de SharePoint sin instalar código en el servidor que ejecuta Microsoft SharePoint Foundation 2010. Por ejemplo, puede crear nuevas categorías de aplicaciones que incluyan aplicaciones de escritura basadas en Microsoft .NET Framework, elementos web interactivos enriquecidos, aplicaciones Microsoft Silverlight y aplicaciones ECMAScript (JavaScript, JScript) que se ejecutan del lado cliente en un elemento web de SharePoint. Por ejemplo:

  • Un líder de equipo crea un sitio de SharePoint que tiene muchas listas necesarias para administrar la misión de su equipo. Desea cambiar estas listas de forma ad-hoc, quizá actualizando asignaciones y estimaciones sobre la base de una hoja de cálculo Open XML, o moviendo elementos de una lista de SharePoint a otra. Desea escribir una pequeña aplicación personalizada para facilitar la administración de las listas.

  • Una compañía de software que vende una aplicación cliente enriquecida tradicional desea integrar bibliotecas de documentos y listas de SharePoint en su aplicación y desea que esta integración sea fluida, o incluso invisible para los usuarios.

  • Un desarrollador de SharePoint desea crear un elemento web enriquecido para una implementación de SharePoint que lleve contenido de las listas a su código web AJAX personalizado. También desea crear una aplicación Silverlight aún más enriquecida que haga lo mismo.

¿Qué tienen todos ellos en común? Pueden usar el modelo de objetos de cliente administrado de SharePoint Foundation 2010 para lograr sus objetivos. El modelo de objetos de cliente administrado de SharePoint Foundation 2010 permite escribir código del lado cliente para trabajar con todos los objetos comunes en sitios de SharePoint. A través del modelo de objetos, puede agregar y quitar listas, agregar, actualizar y eliminar elementos de listas, cambiar documentos de bibliotecas de documentos, crear sitios, administrar permisos de elementos y agregar y quitar elementos web de una página.

Antes, no había muchas opciones. Se podía usar los servicios web para interactuar con listas de SharePoint y otras características, pero era complicado. Si los servicios web no proporcionaban las capacidades necesarias, se podía escribir código del lado servidor para proporcionar un nuevo servicio web (una tarea aún más complicada). Algunos departamentos de TI no permiten el código del lado servidor, o solo permiten crear código escrito por el departamento de TI, por lo que a veces esta opción no era válida. El modelo de objetos de cliente administrado de SharePoint Foundation 2010 permite nuevos tipos de aplicaciones y facilita la escritura de código del lado cliente para interactuar con contenido de SharePoint.

Uso del modelo de objetos de cliente administrado de SharePoint Foundation 2010

Para usar el modelo de objetos de cliente administrado de SharePoint Foundation 2010 (modelo de objetos de cliente), se escribe código administrado basado en .NET Framework que usa una API que se asemeja al modelo de objetos usado en un servidor que ejecuta SharePoint Foundation. El modelo de objetos de cliente tiene clases para obtener acceso a información de la colección de sitios, información de los sitios e información de las listas y elementos de lista.

En el caso de elementos web, se usa una interfaz de programación ECMAScript (JavaScript, JScript) que se asemeja a la API de .NET Framework. En el caso de Silverlight, se usa un subconjunto de la API disponible a través de .NET Framework en el cliente. Aunque gran parte de la información presentada en este artículo es pertinente a las API de JavaScript y Silverlight, este artículo se concentra principalmente en cómo usar el modelo de objetos de cliente administrado de SharePoint Foundation 2010 desde una aplicación cliente basada en .NET Framework.

El modelo de objetos de cliente administrado de SharePoint Foundation 2010 consta de dos ensamblados que contienen cinco espacios de nombres. Si observa las clases disponibles en dichos espacios de nombres, verá que son muchas. No se preocupe; muchas de esas clases son usadas internamente por el modelo de objetos. Solo es importante un subconjunto de estas clases, principalmente aquellas que tienen equivalentes directos a algunas clases familiares en el modelo de objetos de servidor de SharePoint Foundation.

Tabla 1. Clases del lado cliente y equivalentes del lado servidor

Cliente

Servidor

ClientContext

SPContext

Site

SPSite

Web

SPWeb

List

SPList

ListItem

SPListItem

Field

SPField

Tenga en cuenta que el modelo de objetos de cliente administrado de SharePoint Foundation 2010 usa el mismo patrón de nomenclatura heredado para colecciones de sitios y sitios que el modelo de objetos de servidor. La clase Site representa colecciones de sitios y la clase Web representa sitios. La razón por la que es preferible usar estas clases es porque permiten asignar a las variables un nombre que indica si se trata de una colección de sitios o de un sitio, aunque se deben usar las clases Site y Web para declararlas.

En el ejemplo siguiente se muestra cómo asignar un nombre a las variables.

ClientContext clientContext = new ClientContext(siteUrl);
Site siteCollection = clientContext.Site;
Web site = clientContext.Web;

Funcionamiento del modelo de objetos del lado cliente

Una aplicación que usa contenido de SharePoint interactúa con la API de varias formas: llama a métodos y obtiene los valores devueltos, pasa una consulta Lenguaje de marcado de la aplicación de colaboración (CAML) y obtiene los resultados y establece u obtiene propiedades. Después de usar la API para realizar una tarea específica, el modelo de objetos de cliente administrado de SharePoint Foundation 2010 agrupa estos usos de la API en XML y los envía al servidor que ejecuta SharePoint Foundation. El servidor recibe esta solicitud y hace las llamadas correspondientes al modelo de objetos en el servidor, recopila las respuestas, las transforma en notación de objetos JavaScript (JSON) y envía dicha JSON de vuelta al modelo de objetos de cliente administrado de SharePoint Foundation 2010. El modelo de objetos de cliente analiza la JSON y presenta los resultados a la aplicación como objetos de .NET Framework (u objetos de JavaScript para JavaScript). El diagrama siguiente muestra estas interacciones.

Figura 1. El modelo de objetos de cliente administrado de SharePoint Foundation 2010

0ebaeb17-ceb2-43a7-9ebe-22adc04b6137

Es importante tener en cuenta que el usuario controla el momento en que el modelo de objetos de cliente administrado de SharePoint Foundation 2010 inicia el envío del XML al servidor y recibe la JSON del servidor.

El agrupamiento de varias llamadas de método en una sola llamada al servidor está determinado por la realidad de la velocidad de red, la latencia de red y las características de rendimiento deseadas. Si el modelo de objetos de cliente administrado de SharePoint Foundation 2010 interactuara con el servidor en cada llamada de método, el rendimiento del sistema y el aumento del tráfico de la red impedirían que el sistema funcionase correctamente.

Como se ha mencionado, el usuario controla explícitamente el momento en que el modelo de objetos de cliente administrado de SharePoint Foundation 2010 agrupa las llamadas de método y envía una solicitud al servidor. Como parte de este proceso, antes de iniciar la interacción con el servidor, debe especificar explícitamente qué contenido desea recuperar del servidor. Ésta es la principal diferencia entre el modelo de objetos de cliente administrado de SharePoint Foundation 2010 y el modelo de objetos de SharePoint Foundation 2010. Una vez que comprende cómo funciona el modelo, no es complicado usarlo. La forma más sencilla de empezar a entender la diferencia entre ambos es mediante una aplicación sencilla.

Creación de aplicaciones de modelo de objetos de cliente administrado de consola de Windows

Nota

En este artículo se usan aplicaciones de consola de Microsoft Windows para el código de muestra pero se puede usar el mismo método con otros tipos de aplicación.

Para crear la aplicación, debe agregar referencias a dos ensamblados: Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll. Al instalar SharePoint Foundation, se instalan estos ensamblados en el servidor. Los dos ensamblados se encuentran en el siguiente directorio:

%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI

Nota importanteImportante

Para SharePoint Foundation Beta y Microsoft SharePoint Server 2010 Beta, debe copiar los dos ensamblados y colocarlos en una ubicación adecuada en el equipo cliente de desarrollo. Debe buscar estos ensamblados para agregarles referencias cuando configure proyectos que usan el modelo de objetos de cliente administrado de SharePoint Foundation 2010.

Para crear la aplicación

  1. Inicie Microsoft Visual Studio 2010.

  2. En el menú Archivo, elija Nuevo y haga clic en Proyecto.

  3. En el cuadro de diálogo Nuevo proyecto, en el panel Plantillas recientes, expanda Visual C# y después haga clic en Windows.

  4. A la derecha del panel Plantillas recientes, haga clic en Aplicación de consola.

  5. De forma predeterminada, Visual Studio crea un proyecto que tiene como destino .NET Framework 4, pero debe tener como destino .NET Framework 3.5. En la lista de la parte superior del cuadro de diálogo Abrir archivo, seleccione .NET Framework 3.5.

  6. En el cuadro Nombre, escriba el nombre que desee usar para el proyecto, por ejemplo PrimeraAplicaciónApiCliente.

  7. En el cuadro Ubicación, escriba la ubicación donde desee colocar el proyecto.

    Figura 2. Creación de una solución en el cuadro de diálogo Nuevo proyecto

    6fff7a0d-bf31-4042-acb2-72a16fce6e19

  8. Haga clic en Aceptar para crear la solución.

Para agregar referencias al ensamblado Microsoft.SharePoint.Client y al ensamblado Microsoft.SharePoint.Client.Runtime

  1. Las clases que se usan en una aplicación de modelo de objetos de cliente están ubicadas en Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll.Como ya se mencionó anteriormente, antes de agregar las referencias, debe copiar estos ensamblados del servidor que ejecuta SharePoint Foundation al equipo de desarrollo cliente.

  2. En el menú Proyecto, haga clic en Agregar referencia para abrir el cuadro de diálogo Agregar referencia.

  3. Seleccione la pestaña Examinar y navegue a la ubicación en la que colocó Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll.Seleccione ambas DLL y después haga clic en Aceptar , como se muestra en la figura 3.

    Figura 3. Adición de referencias a los ensamblados

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

Para agregar el código de muestra a la solución

  1. En Visual Studio, reemplace el contenido del archivo de origen Program.cs con el código siguiente.

    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. Reemplace la dirección URL del constructor ClientContext(String) con la dirección URL del sitio de SharePoint. Cree y ejecute la solución. En el ejemplo se imprime el título del sitio.

Al igual que con el modelo de objetos de servidor de SharePoint Foundation, se crea un contexto para el sitio de SharePoint al que desea obtener acceso. Después, puede recuperar una referencia al sitio desde el contexto.

La llamada al método ExecuteQuery() hace que el modelo de objetos de cliente administrado de SharePoint Foundation 2010 envíe la solicitud al servidor. No hay tráfico de red hasta que la aplicación llama al método ExecuteQuery().

Un punto importante para tener en cuenta acerca de este ejemplo es que la llamada al método Load() no carga nada, sino que indica al modelo de objetos de cliente que cuando la aplicación llama al método ExecuteQuery(), el usuario desea cargar los valores de la propiedad del objeto siteCollection.

Éste es el modelo que siguen todas las interacciones con el servidor:

  1. El usuario informa al modelo de objetos de cliente administrado deSharePoint Foundation 2010 acerca de las operaciones que desea tomar. Esto incluye el acceso a los valores de propiedades de los objetos (por ejemplo, objetos de la clase List, la clase ListItem y la clase Web), las consultas CAML que desea ejecutar y los objetos como ListItem que desea insertar, actualizar o eliminar.

  2. A continuación, se llama al método ExecuteQuery(). No se produce tráfico de red hasta que se llama al método ExecuteQuery(). Hasta ese momento, la aplicación solo registra las solicitudes del usuario.

Como se aprecia en este ejemplo, de lo más simple, primero se configura una consulta y después se ejecutan las consultas. Esto hace que el modelo de objetos de cliente envíe tráfico al servidor y reciba una respuesta de él. En la siguiente sección se describe el modelo en detalle y se explica el porqué de su diseño y cómo se pueden crear aplicaciones usando el modelo.

Información general del modelo de objetos de cliente administrado de SharePoint Foundation 2010

Hay aspectos específicos del modelo de objetos de cliente que se deben examinar:

  • Métodos que adopta el modelo de objetos de cliente para minimizar el tráfico de red

  • Construcción de consultas

  • Técnicas para mejorar el rendimiento del servidor

  • Creación, actualización y eliminación de objetos de cliente

  • Trabajo con listas muy grandes

Antes de profundizar en estos temas, veamos el problema de la identidad de los objetos.

Uso de identidades de objeto

La idea fundamental de la identidad de objetos es que los objetos de cliente se refieren al objeto correspondiente en el modelo de objetos de servidor de SharePoint Foundation, tanto antes como después de llamar al método ExecuteQuery(), y continúan refiriéndose al mismo objeto a lo largo de varias llamadas al método ExecuteQuery().

Esto significa que cuando se configura la consulta, el modelo de objetos de cliente devuelve objetos que se pueden usar para configurar aún más la consulta antes de llamar al método ExecuteQuery(). Esto permite escribir consultas más complejas antes de iniciar el tráfico hacia y desde el servidor. Puede hacer cosas más interesantes en una sola consulta y eliminar el tráfico de red.

En el ejemplo siguiente se obtiene el objeto de la lista Anuncios y después se recuperan todos los elementos de dicha lista usando la consulta CAML más simple posible.

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"]);
    }
}

Observe la secuencia de este ejemplo:

  1. Primero, el código obtiene un objeto List mediante el método GetByTitle(). Recuerde que este objeto List no contiene datos; no contiene datos en ninguna de sus propiedades hasta que la aplicación llama al método ExecuteQuery().

  2. Después, llama al método GetItems() en el objeto list, aunque dicho objeto list no contenga datos.

  3. Por último, llama al método Load() en el objeto list y en el objeto listItems y, después, llama al método ExecuteQuery().

El punto fundamental acerca de esta secuencia es que el modelo de objetos de cliente recuerda que el objeto list es el objeto que la aplicación inicializó usando el método GetByTitle() y que el modelo de objetos de cliente debería ejecutar la consulta CAML en ese mismo objeto list después de recuperar el objeto list de la base de datos de SharePoint. Cualquier clase que derive de la clase ClientObject tiene esta semántica.

Además, como ya se ha mencionado, es posible continuar usando objetos de cliente para configurar consultas adicionales después de llamar al método ExecuteQuery(). En el ejemplo siguiente, el código carga el método list y llama al método ExecuteQuery(). Después, usa ese objeto de cliente list para llamar al método List.GetItems y después llama al método ExecuteQuery() otra vez. El objeto list conservó su identidad durante toda la llamada al métodoExecuteQuery().

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"]);
    }
}

Algunas propiedades y métodos devuelven objetos o tipos de valor que no derivan de la clase ClientObject. La identidad de objeto de cliente resulta útil para obtener acceso a métodos y propiedades solo cuando dichos métodos y propiedades devuelven objetos de cliente o colecciones de estos objetos. Por ejemplo, algunas clases, como la clase FieldUrlValue y la clase FieldLookupValue, derivan de la clase ClientValueObject y no se pueden usar propiedades que devuelven estos tipos hasta después de la llamada al método ExecuteQuery(). Algunas propiedades devuelven tipos .NET Framework como una cadena o un entero y tampoco se pueden usar propiedades o métodos que devuelven estos tipos hasta después de la llamada al método ExecuteQuery(). Dado que no se pueden usar los valores de ninguna propiedad hasta que dichos valores se rellenan en la llamada ExecuteQuery(), no es posible, por ejemplo, buscar un elemento en una lista, y usar el valor de uno de los campos de dicho elemento para seleccionar elementos en una consulta adicional. Si intenta usar una propiedad antes de que la rellene el método ExecuteQuery(), el modelo de objetos de cliente iniciará una excepción PropertyOrFieldNotInitializedException.

Nota de precauciónPrecaución

La identidad de objeto de cliente es válida para un solo objeto ClientContext. Si se inicializa otro objeto ClientContext al mismo sitio de SharePoint, no se pueden usar objetos de cliente de un contexto de cliente con el otro.

En varios ejemplos que se muestran posteriormente en este artículo se usa el comportamiento de identidad de objeto.

Nota

En este ejemplo no se realiza el control de errores. Si la lista Anuncios no existe, el modelo de objetos de cliente inicia una excepción en la llamada al método ExecuteQuery(). Debe estar preparado para capturar excepciones cuando escriba código que puede fallar si pide objetos que quizá no existen.

Recorte de conjuntos de resultados

SharePoint Foundation suele implementarse en organizaciones con miles de usuarios. Cuando se crea una aplicación que obtiene acceso a SharePoint Foundation a través de la red, tiene sentido crearla de forma tal que use la menor cantidad posible de tráfico de red. Hay varias formas en que el modelo de objetos de cliente puede ayudarle a lograr esto. El método más sencillo es usar expresiones lambda para especificar exactamente qué propiedades debe devolver el modelo de objetos de cliente a la aplicación.

En el ejemplo siguiente se muestra cómo especificar que cuando el modelo de objetos de cliente carga el objeto del sitio, debe cargar solo la propiedad Title y la propiedad Description. Esto reduce el tamaño de respuesta de la JSON del servidor al cliente.

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);
    }
}

De forma predeterminada, si no se incluyen estas expresiones lambda en la llamada al método Load(), se cargará un número mucho mayor de propiedades (pero no todas). En los dos primeros ejemplos se llamó al método Load() sin especificar qué propiedades se cargarían, por lo que el paquete JSON que devolvió el servidor fue algo más grande de lo necesario. Aunque en estos ejemplos pequeños no hay mucha diferencia, cuando se cargan miles de elementos de listas, se puede reducir el tráfico de red si se especifican detenidamente las propiedades necesarias.

Mediante las expresiones lambda se puede especificar una lista de propiedades al método Load(). La reducción del tráfico de red no es la única ventaja que se obtiene al usar expresiones lambda del modelo de objetos de cliente. Más adelante en este artículo se describe cómo filtrar conjuntos de resultados usando expresiones lambda.

A continuación, se muestra un ejemplo en el que se crea una lista y después se le agrega contenido. Esto proporcionará contenido de muestra para trabajar con el resto de este artículo.

Creación y rellenado de una lista

En el ejemplo siguiente se crea una lista y después se le agregan algunos campos y varios elementos.

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();
    }
}

En muchos casos en los que se puede crear un objeto de cliente, la aplicación puede llamar a un método Add que toma como argumento un objeto que especifica información sobre la creación. En este ejemplo se muestra cómo usar la clase ListCreationInformation para crear un objeto List y cómo usar la clase ListItemCreationInformation para crear un objeto ListItem. A menudo se establecen propiedades de la clase de información de creación después de crear una instancia. Como se puede ver, el código establece la propiedad Title y la propiedad TemplateType del objeto ListItemCreationInformation. Tenga en cuenta que para crear una lista, se debe llamar al método Add(), pero para crear un objeto ListItem, se debe llamar al método AddItem(). El método Add() crea una lista en la colección y el método AddItem() crea un solo elemento de lista.

La creación de campos en una lista tampoco usa un método Add, ya que, cuando se crean campos, en realidad no se está creando una instancia de la clase Field. Se está creando una instancia de una clase que deriva de la clase Field. Hay muchas opciones disponibles para estas clases derivadas y el uso de un método Add complicaría demasiado el diseño de una clase FieldCreationInformation. Por esta razón, el modelo de objetos de cliente no incluye esta clase. La forma más sencilla de crear un campo es especificar un bit de XML que defina el campo y pasar dicho XML al método AddFieldAsXml(). Hay un método Add() que se puede usar para crear un campo, pero en lugar de tomar un objeto FieldCreationInformation, toma otro objeto Field como parámetro que usa como prototipo para el campo que se va a crear. Esto resulta útil en otros escenarios.

SugerenciaSugerencia

La sección Detección del esquema de los campos de este artículo muestra una forma sencilla de detectar el XML que se debe especificar para los campos que desea crear.

Tenga en cuenta que, por supuesto, no se agrega ningún objeto a la base de datos de SharePoint hasta que la aplicación llame al método ExecuteQuery().

En este ejemplo hay otro punto interesante a tener en cuenta. Observe que, después de llamar al método AddItem(), el ejemplo establece tres propiedades indizadas. El código establece los valores de los campos que se agregaron antes a la lista. Después de establecer estas propiedades, la aplicación debe llamar al método Update() e informar al modelo de objetos de cliente que dichos objetos se modificaron. El modelo de objetos de cliente no funciona correctamente si no se hace así. El método Update() se usará en ejemplos posteriores cuando se muestre cómo modificar objetos de cliente existentes.

Con los datos que tenemos ahora, veamos algunas formas interesantes de consultarlos y modificarlos.

Uso de CAML para consultar listas

En el ejemplo siguiente se muestra cómo usar CAML para consultar la lista que se creó en el último ejemplo. En este ejemplo se imprimen los elementos Desarrollo de nuestra lista de pruebas.

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();
        }
    }
}

Este ejemplo produce el siguiente resultado.

Title: Develop proof-of-concept.
Category: Development
Estimate: 42

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

Es posible que observe una diferencia entre las expresiones lambda especificadas en este ejemplo y las expresiones lambda del ejemplo presentado en la sección Recorte de conjuntos de resultados. Debe usarse el método de extensión Include() para especificar las propiedades que desee cargar para cada elemento de la colección que se cargue. El parámetro items de la expresión lambda es del tipo ListItemCollection, por lo que, naturalmente, no contiene una propiedad indizada que nos permita especificar qué propiedades cargar para los elementos de la colección. Es necesario llamar al método de extensión Include(), que nos permite especificar qué parámetros de esa colección de elementos secundarios se cargarán. Los parámetros de las expresiones lambda del método de extensión Include() son del mismo tipo que los elementos de la colección. Por lo tanto, puede especificar las propiedades que desea cargar para cada elemento de la colección.

Como ya se ha indicado, no es indispensable comprender la semántica exacta de este uso de expresiones lambda. Simplemente recuerde dos expresiones de codificación:

Si se solicita al modelo de objetos de cliente que cargue ciertas propiedades de un objeto de cliente (no una colección), deben especificarse las propiedades en la expresión lambda que se agregan directamente al método Load().

clientContext.Load(site,
    s => s.Title,
    s => s.Description);

Si se solicita al modelo de objetos de cliente que cargue ciertas propiedades de cada elemento en una colección de objetos de cliente, se usa el método de extensión Include() y se pasan las expresiones lambda que especifican las propiedades deseadas al método Include().

clientContext.Load(
    listItems,
    items => items.Include(
        item => item["Title"],
        item => item["Category"],
        item => item["Estimate"]));

Filtrado de la colección de elementos secundarios devuelta por Load mediante LINQ

Dado que el método de extensión Include() devuelve IQueryable<T>, se puede crear una cadena del método Include() al método de extensión IQueryable<T>.Where. Esto proporciona una forma concisa de filtrar el conjunto de resultados. Esta capacidad se debe usar únicamente cuando se consultan colecciones de objetos de cliente que no sean colecciones de objetos ListItem ya que, aunque se puede usar esta técnica para filtrar colecciones de objetos ListItem, el uso de CAML permite obtener un mejor rendimiento. Esto es sumamente importante, por lo que vale la pena repetirlo:

Nota de precauciónPrecaución

Nunca use el método de extensión IQueryable<T>.Where cuando consulte objetos ListItem. Esto se debe a que el modelo de objetos de cliente evalúa primero el resultado de la consulta CAML, recupera los resultados y después filtra la colección resultante usando LINQ. Si se filtra una lista muy grande usando LINQ en vez de CAML, el modelo de objetos de cliente intentará recuperar todos los elementos de la lista antes de filtrarlos con LINQ y emitirá consultas que requieren demasiados recursos del sistema o la consulta producirá un error. Esta explicación no es fácil de entender a menos que sepa cómo funciona el modelo de objetos de cliente a nivel interno. Debe usar CAML para consultar elementos de listas.

En el ejemplo siguiente se consulta el modelo de objetos de cliente para todas las listas que no están ocultas. Observe que debe incluir una directiva using para el espacio de nombres System.Linq.

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);
    }
}

En mi servidor, este ejemplo produce el siguiente resultado:

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

Uso del método LoadQuery

El método LoadQuery() tiene una función similar a la del método Load(), pero en ciertas circunstancias el modelo de objetos de cliente puede procesar las consultas de forma más eficiente y usar la memoria de forma más eficiente. También permite un estilo de programación más flexible.

La semántica del método LoadQuery() es diferente de la del método Load(). Mientras que el método Load() rellena el objeto de cliente (o la colección de objetos de cliente) con datos del servidor, el método LoadQuery() rellena y devuelve una nueva colección. Esto significa que se puede consultar la misma colección de objetos varias veces y mantener conjuntos de resultados separados para cada consulta. Por ejemplo, se pueden consultar todos los elementos de una lista de proyectos asignados a una cierta persona y, por separado, consultar todos los elementos que tienen una cantidad de horas estimadas que superan un determinado umbral y obtener acceso a ambos conjuntos de resultados al mismo tiempo. También permite que las colecciones excedan el ámbito y que, por lo tanto, se vuelvan aptas para recolección como elementos no utilizados. Las colecciones que se cargan usando el método Load() son aptas para recolección como elementos no utilizados solo cuando la variable del contexto de cliente también excede su ámbito. Aparte de estas diferencias, el método LoadQuery() proporciona la misma función que el método Load().

En el ejemplo siguiente se usa el método LoadQuery() para recuperar una lista de todas las listas del sitio.

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"));
    }
}

Observe que el método LoadQuery() devuelve una nueva colección de listas en la que se puede procesar una iteración. La nueva colección de listas es del tipo IEnumerable<List> en vez de ListCollection.

Hay un aspecto de la semántica del método LoadQuery() al que debe prestarse atención. En el ejemplo anterior, la variable de las listas originales no rellena sus valores de propiedad después de la devolución del método ExecuteQuery(). Si desea rellenar esta lista, debe llamar explícitamente al método Load() y especificar qué propiedades desea cargar.

Aumento del rendimiento mediante el anidamiento de instrucciones Include en LoadQuery

Cuando se llama al método LoadQuery(), se pueden especificar varios niveles de propiedades para cargar. Esto permite al modelo de objetos de cliente optimizar su acceso al servidor que ejecuta SharePoint Foundation reduciendo el número de veces que el modelo de objetos de cliente debe llamar al servidor que ejecuta SharePoint Foundation para recuperar los datos que desea. La siguiente consulta recupera todas las listas del sitio y todos los campos de cada lista. A continuación, los imprime en la consola e indica si cada lista o campo está oculto.

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);
        }
    }
}

Este método permite al elemento de servidor del modelo de objetos de cliente ser más eficiente que si la aplicación cargara primero una lista de las listas y después los campos correspondientes a cada lista.

Filtrado de la colección de elementos secundarios devuelta por LoadQuery mediante LINQ

El método LoadQuery() toma un objeto de tipo IQueryable<T> como parámetro y esto le permite escribir consultas LINQ en vez de CAML para filtrar los resultados. Este ejemplo devuelve una colección de todas las bibliotecas de documentos que no están ocultas.

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);
    }
}

Actualización de objetos de cliente

La actualización de objetos de cliente usando el modelo de objetos de cliente es relativamente simple. Se recuperan los objetos, se modifican las propiedades, se llama al método Update para cada objeto que se cambia y, después, se llama al método ExecuteQuery(). En el ejemplo siguiente se modifican los elementos de la lista de pruebas de la API del cliente, aumentando la estimación de todos los elementos de desarrollo en un 50 por ciento (una operación común).

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();
    }
}

Eliminación de objetos de cliente

La eliminación de objetos de cliente es igual de sencilla. No obstante, hay una dinámica muy importante en torno a la eliminación de objetos de cliente de una colección de objetos de cliente. No se puede procesar una iteración a través de la colección, eliminando objetos. En cuanto se elimina el primer objeto, esto provoca que el iterador de la colección de objetos de cliente deje de funcionar correctamente. El iterador puede iniciar una excepción o completarse sin problemas, pero no visitará todos los elementos de la colección. Debe materializar la colección en una List<T> usando el método ToList y después procesar una iteración en dicha lista eliminando los objetos de cliente.

En el ejemplo siguiente se eliminan los elementos de prueba de nuestra lista de pruebas de la API del cliente.Muestra el uso del método ToList para materializar la colección antes de procesar una iteración en ella:

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();
    }
}

En el ejemplo de código siguiente se muestra el método incorrecto.

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();

Por último, para limpiar la lista de pruebas de la API del cliente, se muestra un ejemplo en el que se elimina la lista y sus elementos.

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();
    }
}

Detección del esquema de los campos

Como se comentó al principio, en esta sección se describe una manera sencilla de detectar el esquema XML que se usa para crear los campos que desea crear en una lista. En primer lugar, en el sitio de SharePoint, cree una lista que contenga columnas configuradas como desee. A continuación, puede usar el ejemplo siguiente para obtener el XML que crea dichos campos.

En el ejemplo siguiente se imprimen los esquemas de campo para los campos que se agregaron a la lista de pruebas de la API del cliente.

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("===============");
            }
        }
    }
}

Cuando se ejecuta después de crear la lista usando el programa de ejemplo de la sección Creación y rellenado de una lista, se obtiene el siguiente resultado.

<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" />
===============

En el ejemplo se eliminan los atributos no necesarios para crear el campo.

Acceso a listas grandes

Las directivas de desarrollo de SharePoint establecen que no se debe intentar recuperar más de 2000 elementos en una sola consulta. Si existe esta posibilidad en la aplicación, considere la posibilidad de usar el elemento RowLimit en sus consultas CAML para limitar la cantidad de datos que el modelo de objetos de cliente recupera para la aplicación. A veces, deberá obtener acceso a todos los elementos de una lista que puede contener más de 2000 elementos. En ese caso, se recomienda paginar los elementos en grupos de 2000. En esta sección se describe un método de paginación usando la propiedad ListItemCollectionPosition.

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();
        }
    }
}

Este ejemplo produce el siguiente resultado.

  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

Procesamiento asincrónico

Si se crea una aplicación que debe adjuntarse a sitios de SharePoint que pueden no estar disponibles, o si se debe invocar periódicamente consultas que llevan mucho tiempo, conviene considerar la posibilidad de usar el procesamiento asincrónico. Esto permite a la aplicación continuar respondiendo al usuario mientras la consulta se ejecuta en un subproceso separado. En el subproceso principal, se puede configurar un temporizador para que avise si la consulta excede el umbral de tiempo. También se puede mantener informado al usuario acerca del estado de la consulta y, una vez finalizada la consulta, se pueden mostrar los resultados.

La versión JavaScript del modelo de objetos de cliente y la versión Silverlight (cuando modifica la interfaz de usuario) usan procesamiento asincrónico. El tema Data Retrieval Overview del SDK de SharePoint 2010 contiene ejemplos de cómo usar el procesamiento asincrónico con JavaScript y Silverlight.

Cuando se crea una aplicación tradicional basada en .NET Framework, como una aplicación Windows Forms o WPF, puede ser preferible usar el procesamiento asincrónico. En el ejemplo siguiente se usa el método BeginInvoke para ejecutar una consulta de forma asincrónica. Observe que el código pasa una expresión lambda de instrucción al método BeginInvoke, lo que hace que sea conveniente crear este patrón, ya que la expresión lambda de instrucción puede referirse a variables automáticas en el método que la contiene. Como puede ver, la expresión lambda de instrucción tiene acceso a la variable clientContext y a la variable newListCollection . Las clausuras de Microsoft Visual C# hacen que la función de idioma sea tal como se espera.

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);
    }
}

El ejemplo produce el siguiente resultado:

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

Recursos adicionales

Para más información, vea los siguientes recursos: