CSOM (Modelo Objeto Clientes) para NET – Buenas Prácticas

Mostraremos a continuación algunos aspectos que van a mejorar nuestro código cuando estemos usando el modelo de objetos de cliente de .NET (CSOM) para SharePoint.
1. Hacer una llamada a que cargue el contexto: ClientContext.ExecuteQuery antes de acceder a los valores de cualquier propiedad. El modelo de clientes para SharePoint (CSOM), requiere que se use un patrón parecido a SQL: declarar lo que se quiere ejecutar, es decir declare lo que se necesita antes de acceder a los datos. Por ejemplo, el siguiente código, va a intentar desplegar el título de un sitio de SharePoint, pero va a arrojar una excepción:
C#
// Empezando con el objeto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
label1.Text = web.Title;
Este código falla porque el modelo de objetos de SharePoint para .NET (CSOM) debe seguir los siguientes pasos:
* Construir una consulta.
* Ejecutar la Consulta.
* Leer el resultado.
En CSOM, cuando usted llama a un método está construyendo una consulta. Las consultas se van acumulando y no se envian al servidor hasta que se invoca al método ExecuteQuery. El siguiente ejemplo muestra el código que se necesita para desplegar el título de un sitio de SharePoint. Va a necesitar agregar una sentencia “using” a System.Linq. También un alias a la sentencia using para el espacio de nombres Microsoft.SharePoint.Client, de esta manera se puede referir a sus clases sin ser ambiguo. Ejemplo: using SP = Microsoft.SharePoint.Client;.
C#
// Empezando con el objecto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
context.Load(web, w => w.Title);
context.ExecuteQuery();
label1.Text = web.Title;
La diferencia entre los dos ejemplos es que se agregaron estas líneas:
context.Load(web, w => w.Title);
context.ExecuteQuery();
La primera línea crea un consulta para la propiedad “Title” del sitio, mientras que la segunda línea ejecuta la consulta.
2. No usar objetos por valor retornados por métodos o propiedades en la misma consulta
Cuando un objeto por valor es retornado de un método o propiedad, no puede usar ese objeto hasta después de haber ejecutado la consulta. Ejemplo, el siguiente código intenta crear una lista de SharePoint que tiene el mismo título que el sitio de SharePoint, pero arroja una excepción.
C#
// Empezando con el objecto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
ListCreationInformation creationInfo = new ListCreationInformation();
creationInfo.Description = web.Title;
creationInfo.Title = web.Title;
List newList = web.Lists.Add(creationInfo);
Una excepción es arrojada porque la propiedad no está disponible antes de ejecutar efectivamente la consulta. Usted declararía una variable local para almacenar el valor de web.Title, y usaría esa variable local para la creación del sitio. En el modelo de objetos CSOM para SharePoint usted no puede crear una variable local, deberá partir la funcionalidad en 2 consultas separadas, como se muestra en el siguiente ejemplo. También va a necesitar agregar una sentencia using para System.Linq y una alias al espacio de nombres Microsoft.SharePoint.Client para evitar las ambigüedades cuando se refiera a sus clases, de esta manera: using SP = Microsoft.SharePoint.Client;.
C#
// Empezando con el objeto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
context.Load(web, w => w.Title);
context.ExecuteQuery();
ListCreationInformation creationInfo = new ListCreationInformation();
creationInfo.Description = web.Description;
creationInfo.Title = web.Title;
SP.List newList = web.Lists.Add(creationInfo);
context.ExecuteQuery();
La diferencia son las siguientes líneas que cargan la propiedad que se necesita primero y luego se utiliza.
context.Load(web, w => w.Title);
context.ExecuteQuery();
3.Agrupar la petición de datos en el mismo objeto para mejorar la performance
Cuando este leyendo diferentes datos del mismo objeto, debería intentar obtener todo en una sola consulta, esto es una sola invocación al método Load(T, []). El siguiente código muestra 2 formas de devolver el título del sitio y la descripción de la lista “Announcements”. Para compilar este código va a necesitar agregar una sentencia using a System.Linq. Tambien deberá agregar un alias al espacio de nombres Microsoft.SharePoint.Client para evitar las ambigüedades de esta manera: using SP = Microsoft.SharePoint.Client;.
C#
static void Metodo1()
{
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
SP.List list = web.Lists.GetByTitle(“Announcements”);
context.Load(web, w => w.Title, w => w.Description);
context.Load(list, l => l.Description);
context.ExecuteQuery();
}
static void Metodo2()
{
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
SP.List list = web.Lists.GetByTitle(“Announcements”);
context.Load(web, w => w.Title);
context.Load(list, l => l.Description);
context.Load(web, w => w.Description);
context.ExecuteQuery();
}
Estos 2 métodos no son igual de eficientes. En el Método 1, el código que trae el título del sitio y la descripción de la lista esta agrupado. Mientras que en el Método 2, el código que retorna el título del sitio y la descripción está separado por otras acciones. Esto significa que el Método 2, va a disparar 2 consultas por separado en el mismo objeto “web” y va a haber 2 conjuntos de resultados para el mismo web. Porque la librería cliente (CSOM), intenta retornar datos consistentes, el segundo conjunto de resultados, va a incluir tanto el titulo como la descripción. Puede pensar en dicho código de la siguiente manera:
SQL
Method1:
SELECT Title, Description FROM Webs WHERE …
SELECT Description FROM Lists WHERE …
Method2:
SELECT Title FROM Webs WHERE …
SELECT Description FROM Lists WHERE …
SELECT Title, Description FROM Webs WHERE …
4. Especifique cuales propiedades de los objetos quiere retornar
En el modelo de objetos de servidor si obtiene un objeto SPWeb, puede inspeccionar todas las propiedades. En SQL, para obtener todas las columnas de una tabla puede ejecutar:
SQL
SELECT * FROM Webs
En la librería de cliente, ni el Load ningún otro método devuelva todas las propiedades, entonces debería explícitamente especificar que es lo que quiere. Por ejemplo, el siguiente código retorna el objeto website sin especificar que propiedades retornar. Trata entonces de leer 2 propiedades y una de ellas no es las que se carga automáticamente. El código arroja una excepción:
C#
// Empezando con el objeto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
context.Load(web);
context.ExecuteQuery();
Console.WriteLine(web.Title);
Console.WriteLine(web.HasUniqueRoleAssignments);
Para que el código anterior funcione correctamente lo tiene que actualizar de la siguiente forma:
C#
// Empezando con el objeto ClientContext, el constructor requiere una URL al sitio de SharePoint.t.
ClientContext context = new ClientContext(“http://SiteUrl”);
Web web = context.Web;
context.Load(web);
context.Load(web, web => web.HasUniqueRoleAssignments);
context.ExecuteQuery();
Console.WriteLine(web.Title);
Console.WriteLine(web.HasUniqueRoleAssignments);
5. Usar “conditional scope” para testear precondiciones antes de cargar los datos
Para ejecutar código de manera condicional, establezca un “conditional scope” usando un objeto ConditionalScope. Por ejemplo, retorna una propiedad de la lista cuando esta no es nula:
C#
// Empezando con el objeto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
SP.List list = context.Web.GetCatalog(ListTemplateType.WebPartCatalog);
BasePermissions perm = new BasePermissions();
perm.Set(PermissionKind.ManageLists);
ConditionalScope scope =
new ConditionalScope(context,
() => list.ServerObjectIsNull && context.Web.DoesUserHavePermissions(perm).Value);
using (scope.StartScope())
{
context.Load(list, l => l.Title);
}
context.ExecuteQuery();
label1.Text = scope.TestResult.Value;
if (scope.TestResult.Value)
{
label1.Text = list.Title;
}
6. Usar lo que conoce como “exception handling scope” para atrapar excepciones
Este ejemplo muestra cómo crear y usar manejo de excepciones con el objeto ExceptionHandlingScope. El escenario es actualizar la descripción de una lista y habilitar la creación de carpetas. Esta la posibilidad de que la lista pueda no existir.
C#
// Empezando con el objeto ClientContext, el constructor requiere una URL al sitio de SharePoint.
ClientContext context = new ClientContext(“http://SiteUrl”);
ExceptionHandlingScope scope = new ExceptionHandlingScope(context);
using (scope.StartScope())
{
using (scope.StartTry())
{
List fooList = context.Web.Lists.GetByTitle(“Sample”);
fooList.Description = “In Try Block”;
fooList.Update();
}
using (scope.StartCatch())
{
// Assume that if there’s an exception,
// it can be only because there was no “Sample” list.
ListCreationInformation listCreateInfo = new ListCreationInformation();
listCreateInfo.Title = “Sample”;
listCreateInfo.Description = “In Catch Block”;
listCreateInfo.TemplateType = (int)ListTemplateType.Announcements;
List fooList = context.Web.Lists.Add(listCreateInfo);
}
using (scope.StartFinally())
{
List fooList = context.Web.Lists.GetByTitle(“Sample”);\
fooList.EnableFolderCreation = true;
fooList.Update();
}
}
context.ExecuteQuery();