Share via


 

Por Gustavo Velez

MVP de SharePoint

http://www.gavd.net

 

El Modelo de Objetos de Cliente de SharePoint 2010 y OpenXML: una poderosa combinación

Nota: La información de este artículo y el código fuente del ejemplo adjunto han sido realizados en base a la Beta 2 de SharePoint 2010.

Uno de los avances más importantes de SharePoint 2010 es el extenso Modelo de Objetos de Cliente del que dispone. Hasta esta versión, todas las personalizaciones creadas para SharePoint tenían que ser instaladas físicamente en los servidores pues, fuera del uso del sistema de Servicios Web, era imposible hacer que aplicaciones remotas se comunicaran con SharePoint. El Modelo de Objetos de Cliente acepta la creación de software que ejecuta directamente en los computadores cliente, permitiendo una flexibilidad de arquitectura desconocida hasta ahora, y agregándole nuevas herramientas al sistema para que el desarrollador pueda buscar rutas diferentes para solucionar problemas.

OpenXML es el marco de trabajo que los documentos de Office utilizan para crear archivos de contenido. OpenXML ha sido estandarizado y reemplaza los formatos utilizados en versiones de Office anteriores a 2007. El Modelo de Objetos de OpenXML permite crear, eliminar y editar documentos de Word, Excel y PowerPoint de una forma rápida y segura.

La combinación del Modelo de Objetos de Cliente de SharePoint 2010 y OpenXML abre nuevas perspectivas de interacción entre información mantenida local- y repartidamente en los computadores de los usuarios e información mantenida remota y centralmente en los servidores de SharePoint.

El Modelo de Objetos de Cliente de SharePoint 2010

Uno de los problemas con los que se enfrentan desarrolladores de aplicaciones SharePoint 2007 es que su Modelo de Objetos no se puede usar “a distancia”, es decir, es imposible crear aplicaciones que ejecuten localmente en los computadores de usuarios  pues los compilados siempre deben ser instalados en los servidores de SharePoint mismos. La única excepción es utilizar el sistema de Servicios Webs de SharePoint, pero, aunque los Servicios cubren un gran rango de funcionalidad por defecto, no son completos, crear nuevos Servicios y conectarlos a SharePoint no es una tarea sencilla (y de todas formas tienen que ser instalados en los servidores) y su rendimiento no es suficiente para sistemas con cargas de usuarios elevadas.

El Modelo de Objetos de SharePoint 2010 (Foundation y Server) ofrece la solución, presentando las clases y métodos que los desarrolladores necesitan para crear software que, al mismo tiempo, pueda ser instalado y ejecutado localmente en los computadores cliente, y pueda interactuar “a distancia” con los Portales de SharePoint.

SharePoint 2010 dispone de cuatro variaciones del Modelo de Objetos de Cliente: Modelo de Objetos de Cliente Manejado, Silverlight, ECMAScript y REST. El Modelo de Objetos Manejado ofrece un subconjunto de las instrucciones que ofrece el Modelo de Objetos de Servidor que puede ser utilizado en forma muy similar, es Orientado a Objetos y utiliza una sintaxis muy parecida para obtener y manipular información en las Colecciones de Sitios, Sitios, Listas y Elementos de Listas. Por cuestiones de seguridad del servidor, las clases relativas a la Administración del servidor no están presentes en el Modelo y solo se pueden utilizar los objetos desde Colección de Sitios hacia abajo (es decir, no es posible manejar Aplicaciones Web). Tenga en cuenta que no existe diferencia en programación y utilización de los cuatro tipos de Modelos para ser utilizados con SharePoint Foundation o Server: los ensamblados referenciados son únicos y proveen exactamente la misma funcionalidad con cualquiera de las versiones de SharePoint 2010; tampoco es necesario instalar ningún componente extra si se va a utilizar SharePoint Server.

OpenXML

El formato de archivos OpenXML describe la estructura de los archivos utilizados por Microsoft Office Word, Excel y PowerPoint. El formato define la organización interna de la estructura y la sintaxis de XML utilizada en cada uno de los componentes del archivo. OpenXML es un estándar reconocido por ECMA e ISO/IEC y Microsoft ha liberado software para trabajar programáticamente con sus archivos (el “Open XML SDK 2.0 for Microsoft Office”, https://www.microsoft.com/downloads/details.aspx?FamilyID=c6e744e5-36e9-45f5-8d8c-331df206e0d0&DisplayLang=en).

De hecho, un archivo .docx (Word), .xslx (Excel) o .pptx (PowerPoint) no es más que un archivo .zip con una serie de directorios y archivos, de tal forma que la extensión puede ser cambiada a .zip para abrirlo y revisar su contenido. Los archivos internos consisten de files XML con el contenido del documento y otros recursos como imágenes. Las herramientas de programación presentes en el OpenXML SDK permiten realizar el trabajo de abrir el archivo, extraer la información, modificarla y comprimirla de nuevo de forma programática. La Figura 1 muestra un ejemplo de la arquitectura interna de un archivo Excel.

Figura 1. Arquitectura de un archivo .xslx de OpenXML

 

Un caso de utilización

Como ejemplo de utilización del Modelo de Objetos de Cliente de SharePoint 2010 en conjunto con OpenXML se puede pensar en un escenario en donde es necesario guardar el contenido (texto e imágenes) de una presentación de PowerPoint en un sitio de SharePoint. SharePoint dispone de una Biblioteca especializada para guardar presentaciones de PowerPoint, pero allí solo es posible almacenar la presentación completa, no su contenido separado en texto y figuras. El ejemplo muestra una aplicación cliente de Windows Presentation Foundation (aunque podría utilizarse un aplicación Windows tradicional) que recibe como parámetros de entrada la presentación PowerPoint y el URL del sitio SharePoint y realiza el siguiente proceso:

-          Abre el archivo de la presentación y busca el texto y las figuras en ella utilizando OpenXml

-          Crea un documento Word con el texto presente en cada diapositiva de la presentación usando OpenXML

-          Crea una Biblioteca de Documentos en SharePoint con un campo adicional y un folder en ella (Modelo de Objetos Manejado de Cliente)

-          Sube cada uno de los documentos Word y figuras al folder dentro de la Biblioteca y modifica el campo creado adicionalmente usando el Modelo de Objetos de Cliente

-          Eventualmente elimina la Biblioteca, usando también el Modelo de Objetos de Cliente

Comience creando un proyecto del tipo Windows-WPF Application en Visual Studio 2010 (note que se puede utilizar cualquier versión del Framework DotNet para compilarlo, mientras sea igual o superior a 3.5). Para trabajar con OpenXML es necesario descargar primero el OpenXML SDK indicado al principio e instalarlo en el computador de desarrollo. Cree una referencias a DocumentFormat.OpenXml (C:\Program Files (x86)\Open XML SDK\V2.0\lib, ruta por defecto para un sistema de 64 bits o C:\Program Files\Open XML SDK\V2.0\lib para uno de 32). Para crear las referencias necesarias a los ensamblados del Modelo de Objetos de Cliente de SharePoint, hay dos diferentes casos a analizar:

-          Si se está desarrollando en un computador con SharePoint instalado localmente, cree referencias a  Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll que se pueden encontrar en la ruta C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\

-          Si el computador de desarrollo no tiene SharePoint 2010 instalado, copie los dos dlls indicados en el parágrafo anterior desde un servidor de SharePoint a un directorio local y referéncielos desde allí con Visual Studio

Cree directivas using a:

using DocumentFormat.OpenXml;

using PR = DocumentFormat.OpenXml.Presentation;

using DocumentFormat.OpenXml.Packaging;

using DocumentFormat.OpenXml.Drawing;

using WP = DocumentFormat.OpenXml.Wordprocessing;

using COM = Microsoft.SharePoint.Client;

using System.IO;

Porque existen propiedades y métodos con los mismos nombres entre Presentation y Wordprocessing es necesario usar un identificador; por el mismo problema es necesario eliminar la directiva “using System.Windows.Documents;” si ha sido introducida por defecto.

La Interface de Usuario se ha mantenido bastante sencilla para no complicar la programación. Figura 2 muestra que consiste de un área a donde se puede arrastrar el archivo PowerPoint a examinar, dos casillas para indicar el URL del Sitio SharePoint y el nombre de la Biblioteca y un botón que inicia todo el proceso. En la casilla adicional se presenta información sobre lo que el programa está haciendo y el ultimo botón permite eliminar la Biblioteca.

Figura 2. Interface de Usuario del ejemplo

El evento del botón “Procesar” es el centro de control desde donde todo el proceso se dirige:

        private void btnProcesar_Click(object sender, RoutedEventArgs e)

        {

            Dictionary<int, LinkedList<string>> todosLosTextos = new Dictionary<int, LinkedList<string>>();

            Dictionary<int, LinkedList<byte[]>> todasLasFiguras = new Dictionary<int, LinkedList<byte[]>>();

            //Trabajando con OpenXML para leer las diapositivas de PowerPoint

            using (PresentationDocument documentoPresentacion = PresentationDocument.Open(txtPowerPoint.Text, false))

            {

                //Abrir y Leer la presentacion. Retorna dos Dictionary<> con los textos e imagenes encontrados

                int numeroDiapositivas = DarNumeroDiapositivas(documentoPresentacion);

                for (int Contador = 1; Contador <= numeroDiapositivas; Contador++)

                {

                    LinkedList<string> myTexto = DarTodoElTextoEnDiapositiva(documentoPresentacion, Contador);

                    todosLosTextos.Add(Contador, myTexto);

                    LinkedList<byte[]> misFiguras = DarTodasLasImagenes(documentoPresentacion, Contador);

                    todasLasFiguras.Add(Contador, misFiguras);

                }

                txtMensaje.Text += "PowerPoint leido\n";

            }

            //Trabajando con el Modelo de Objetos de Cliente de SharePoint y OpenXML (para crear documentos Word)

            using (COM.ClientContext myContexto = new COM.ClientContext(txtUrlSitio.Text))

            {

                //Crear la Lista

                CrearLista(myContexto);

                txtMensaje.Text += "Lista creada\n";

                //Crear Campo en la Lista

                CrearCampo(myContexto);

                txtMensaje.Text += "Campo creado en la Lista\n";

                //Crear Carpeta

                CrearCarpeta(myContexto);

                txtMensaje.Text += "Carpeta creada en la Lista\n";

                //Crear Documentos Word

                Dictionary<int, byte[]> misDocumentos = CrearDocumentos(todosLosTextos);

                txtMensaje.Text += "Documentos creados\n";

                //Subir Documentos a la Lista

                Dictionary<int, string> misTextos = DarTextoDocumentos(todosLosTextos);

                SubirDocumentos(myContexto, misDocumentos, misTextos);

                txtMensaje.Text += "Documentos en la Lista\n";

                //Subir Figuras a la Lista

                SubirFiguras(myContexto, todasLasFiguras);

                txtMensaje.Text += "Figuras en la Lista\n";

            }

        }

Las dos primeras líneas crean dos diccionarios que contienen todos los textos y todas las figuras encontradas en la presentación. La primera parte del código crea un objeto “documentoPresentacion” que es una representación binaria del archivo PowerPoint y procesa la parte de OpenXML. La rutina “DarNumeroDiapositivas” retorna un integer indicando la cantidad de diapositivas que contiene la presentación, y el bucle siguiente examina cada una de ellas para extraer sus textos (“DarTodoElTextoEnDiapositiva”) y figuras (“DarTodasLasImagenes”). La segunda parte se encarga, usando el Modelo de Objetos de Cliente, del proceso de crear la Biblioteca (“CrearLista”), crear el campo adicional en ella (“CrearCampo”),  crear el folder (“CrearCarpeta”), crear los documentos Word con el texto (“CrearDocumentos”) y subir tanto los documentos (“SubirDocumentos”) como las figuras (“SubirFiguras”) a la Biblioteca. Un importante aspecto del trabajo con el Modelo de Objetos de Cliente es que es indispensable crear un objeto con el contexto del sitio de SharePoint que representa el medio en donde se van a subir los documentos. Tenga en cuenta que para simplificar el código no se ha agregado ningún tipo de validación ni de manejo de errores, por lo que los valores en la Interface tienen que ser validos y se tiene que usar una presentación de PowerPoint, ningún documento de otro tipo puede ser utilizado.

La rutina de OpenXml para encontrar el numero de diapositivas utiliza el método “Count” de los elementos presentes en la presentación:

        private int DarNumeroDiapositivas(PresentationDocument documentoPresentacion)

        {

            int contadorDiapositivas = 0;

            PresentationPart partePresentacion = documentoPresentacion.PresentationPart;

            PR.Presentation unaPresentation = partePresentacion.Presentation;

            contadorDiapositivas = unaPresentation.SlideIdList.Elements<PR.SlideId>().Count();

            return contadorDiapositivas;

        }

Y la rutina para leer el texto en cada una de las diapositivas es similar:

        private LinkedList<string> DarTodoElTextoEnDiapositiva(PresentationDocument documentoPresentacion, int indexeDiapositiva)

        {

            PresentationPart partePresentacion = documentoPresentacion.PresentationPart;

            PR.Presentation unaPresentacion = partePresentacion.Presentation;

            var diasIds = unaPresentacion.SlideIdList.ChildElements;

            string diasParteRelacionId = (diasIds[indexeDiapositiva - 1] as PR.SlideId).RelationshipId;

            SlidePart diasParte = (SlidePart)partePresentacion.GetPartById(diasParteRelacionId);

            return DarTodoElTextoEnParteDiapositiva(diasParte);

        }

Cada diapositiva consiste de una parte del tipo “SlidePart” emparejada por un identificador dentro de la presentación (objecto “Presentation”). La subrutina “DarTodoElTextoEnParteDiapositiva” extra el texto del código XML que lo rodea:

        private LinkedList<string> DarTodoElTextoEnParteDiapositiva(SlidePart diasParte)

        {

            LinkedList<string> todosLosTextos = new LinkedList<string>();

            foreach (var unParagrafo in diasParte.Slide.Descendants<Paragraph>())

            {

                StringBuilder textoParagrafo = new StringBuilder();

                foreach (var unTexto in unParagrafo.Descendants<DocumentFormat.OpenXml.Drawing.Text>())

                    textoParagrafo.Append(unTexto.Text);

                if (textoParagrafo.Length > 0)

                    todosLosTextos.AddLast(textoParagrafo.ToString());

            }

            return todosLosTextos;

        }

El texto está contenido dentro de parágrafos del tipo “Paragraph”, y cada parágrafo es extraído y agregado a un StringBuilder y retornado en una lista generic.

La rutina para extraer las Figuras sigue la misma estructura a la para extraer los textos:

        public static LinkedList<byte[]> DarTodasLasImagenes(PresentationDocument documentoPresentacion, int indexeDiapositiva)

        {

            LinkedList<byte[]> todasLasImagenes = new LinkedList<byte[]>();

            PresentationPart partePresentacion = documentoPresentacion.PresentationPart;

            PR.Presentation unaPresentacion = partePresentacion.Presentation;

            var diasIds = unaPresentacion.SlideIdList.ChildElements;

            string diasParteRelacionId = (diasIds[indexeDiapositiva - 1] as PR.SlideId).RelationshipId;

            SlidePart diasParte = (SlidePart)partePresentacion.GetPartById(diasParteRelacionId);

            List<ImagePart> figuraPartes = new List<ImagePart>();

            diasParte.GetPartsOfType<ImagePart>(figuraPartes);

            foreach (ImagePart figuraParte in figuraPartes)

            {

                if (figuraParte != null)

                {

                    Stream myStream = figuraParte.GetStream();

                    int longitudStream = Convert.ToInt32(myStream.Length);

                    byte[] misBytes = new byte[longitudStream];

                    int bytesParaLeer = myStream.Read(misBytes, 0, longitudStream);

                    todasLasImagenes.AddLast(misBytes);

                }

            }

            return todasLasImagenes;

        }

El objeto que contiene la diapositiva “diasParte” contiene una lista con todas las figuras en ella, que es guardado en una lista generic y luego leídas una por una en un bucle que convierte cada imagen a un byte array. Al final la lista generic es retornada conteniendo todas las figuras en forma binaria.

Teniendo todo el contenido salvado en sus variables respectivas se puede comenzar a utilizar el Modelo de Objetos para trabajar con SharePoint. Primero se debe crear la Biblioteca:

        private void CrearLista(COM.ClientContext myContexto)

        {

            COM.Web myWeb = myContexto.Web;

            COM.ListCreationInformation listCreationInfo = new COM.ListCreationInformation();

            listCreationInfo.Title = txtNombreLista.Text;

            listCreationInfo.TemplateType = (int)COM.ListTemplateType.DocumentLibrary;

            COM.List myLista = myWeb.Lists.Add(listCreationInfo);

            myLista.OnQuickLaunch = true;

            myLista.Update();

            myContexto.ExecuteQuery();

        }

Un objeto del tipo “ListCreationInformation” se encarga de crear la Biblioteca, asignarle un nombre y un tipo (“DocumentLibrary”). La nueva Biblioteca se agrega a la colección de Listas y se indica que debe aparecer en el menú de acceso rápido. Finalmente, el método “ExecuteQuery” se encarga de enviar toda la información hacia SharePoint.

Una vez creada la Biblioteca se le puede agregar uno o más campos adicionales:

        private void CrearCampo(COM.ClientContext myContexto)

        {

            COM.Web myWeb = myContexto.Web;

            COM.List myLista = myWeb.Lists.GetByTitle(txtNombreLista.Text);

            COM.Field myCampo = myLista.Fields.AddFieldAsXml("<Field DisplayName='Contenido' Type='Text' />",

                        true, COM.AddFieldOptions.DefaultValue);

            myContexto.ExecuteQuery();

        }

En este caso se le añade un campo de tipo texto a la Biblioteca. Note que es indispensable utilizar una consulta CAML pues el Modelo de Objetos de Cliente solo dispone de un método “AddFieldAsXml” para añadir campos. Como de costumbre, el método ExecuteQuery se encarga de serializar la información hacia SharePoint.

Finalmente, crear una carpeta sigue aproximadamente las mismas líneas de código:

        private void CrearCarpeta(COM.ClientContext myContexto)

        {

            string NombreCarpeta = System.IO.Path.GetFileNameWithoutExtension(txtPowerPoint.Text);

            COM.Web myWeb = myContexto.Web;

            COM.List myLista = myContexto.Web.Lists.GetByTitle(txtNombreLista.Text);

            COM.FolderCollection misCarpetas = myWeb.Folders;

            COM.Folder nuevaCarpeta = misCarpetas.Add(txtUrlSitio.Text + "/" + txtNombreLista.Text +

                                    "/" + NombreCarpeta);

            myLista.Update();

            myContexto.ExecuteQuery();

        }

En este caso el método Add de la colección de fólderes se encarga de agregarla utilizando el URL de la Biblioteca.

Para crear los documentos World es necesario recurrir de nuevo a OpenXml:

        private Dictionary<int, byte[]> CrearDocumentos(Dictionary<int, LinkedList<string>> todosLosTextos)

        {

            Dictionary<int, byte[]> misDocumentos = new Dictionary<int, byte[]>();

            foreach (KeyValuePair<int, LinkedList<string>> myTexto in todosLosTextos)

            {

                int DiaNumero = myTexto.Key;

                LinkedList<string> DiaTexto = myTexto.Value;

                using (MemoryStream myStream = new MemoryStream())

                {

                    using (WordprocessingDocument paqueteDocumento = WordprocessingDocument.Create(myStream, WordprocessingDocumentType.Document))

                    {

                        WP.Body myBody = new WP.Body();

                        WP.Table myTabla = new WP.Table();

                        foreach (string unRenglon in DiaTexto)

                        {

                            WP.TableRow colRow = new WP.TableRow();

                            WP.TableCell colCell = new WP.TableCell();

                            colCell.Append(new WP.Paragraph(new WP.Run(new WP.Text(unRenglon))));

                            colRow.Append(colCell);

                            myTabla.Append(colRow);

                        }

                        myBody.Append(myTabla);

                        paqueteDocumento.AddMainDocumentPart();

                        paqueteDocumento.MainDocumentPart.Document = new WP.Document(myBody);

                        paqueteDocumento.Close();

                        misDocumentos.Add(DiaNumero, myStream.ToArray());

                    }

                }

            }

            return misDocumentos;

        }

El proceso de crear documentos con OpenXML es el inverso a leerlos: primero es necesario crear un contenedor para recibir el documento, en este caso es un MemoryStream para mantenerlo en memoria (se puede utilizar también un archivo físico, pero en este caso es más fácil para manipular si esta todo en la memoria). Dentro del documento Word que se está creando se agrega una tabla en el cuerpo del documento, y un renglón conteniendo cada uno de los textos. Note que es necesario crear un parágrafo, que es el contenedor que Word utiliza para mantener su contenido individual. Al final de la rutina se crea una parte principal de documento (método “AddMainDocumentPart”), se añade el cuerpo a esta parte y se cierra el documento, lo que crea el archivo .docx (en memoria, en este caso, como se ha indicado).

Las únicas actividades que faltan son subir los documentos y figuras a la Biblioteca. La rutina “SubirDocumentos” se encarga del trabajo utilizando el Modelo de Objetos de Cliente:

        private void SubirDocumentos(COM.ClientContext myContexto, Dictionary<int, byte[]> misDocumentos, Dictionary<int, string> misTextos)

        {

            foreach (KeyValuePair<int, byte[]> myDocumento in misDocumentos)

            {

                int DiaNumero = myDocumento.Key;

                byte[] DiaDocumento = myDocumento.Value;

                string NombreCarpeta = System.IO.Path.GetFileNameWithoutExtension(txtPowerPoint.Text);

                COM.Web myWeb = myContexto.Web;

                COM.List myLista = myWeb.Lists.GetByTitle(txtNombreLista.Text);

                COM.Folder myCarpeta = myWeb.GetFolderByServerRelativeUrl(txtNombreLista.Text + "/" + NombreCarpeta);

                COM.FileCreationInformation fileCreationInfo = new COM.FileCreationInformation();

                fileCreationInfo.Content = DiaDocumento;

                fileCreationInfo.Url = txtUrlSitio.Text + "/" + txtNombreLista.Text + "/" +

                                       NombreCarpeta + "/dia-" + DiaNumero.ToString() + ".docx";

                COM.File myFile = myCarpeta.Files.Add(fileCreationInfo);

                myLista.Update();

                myContexto.ExecuteQuery();

                //Cambiar el campo de contenido

                COM.FileCollection myFiles = myCarpeta.Files;

                COM.ListItem myItem = myFiles[DiaNumero - 1].ListItemAllFields;

                string unTexto = misTextos[DiaNumero];

                if (unTexto.Length > 250) unTexto = unTexto.Remove(250);  //Campo es de texto y solo puede contener 256 caracteres

                myItem["Contenido"] = unTexto;

                myItem.Update();

                myContexto.ExecuteQuery();

            }

        }

La primera parte de la rutina crea referencias al Sitio, Lista y carpeta a utilizar y por medio de la clase FileCreationInformation se sube el documento a la carpeta señalada. La parte final del código tiene como tarea modificar el campo personalizado creado en la Biblioteca, para lo que es necesario obtener una referencia al elemento acabado de subir a la carpeta. Note que el texto se recorta a 250 caracteres pues se está usando un campo de texto sencillo.

El código para subir las Figuras es de hecho igual al para subir los textos, con la única diferencia que el campo extra no se modifica con información:

        private void SubirFiguras(COM.ClientContext myContexto, Dictionary<int, LinkedList<byte[]>> misFiguras)

        {

            foreach (KeyValuePair<int, LinkedList<byte[]>> myFigura in misFiguras)

            {

                int DiaNumero = myFigura.Key;

                LinkedList<byte[]> DiasDocumento = myFigura.Value;

                int FiguraNumero = 0;

                foreach (byte[] DiaFigura in DiasDocumento)

                {

                    FiguraNumero++;

                    string NombreCarpeta = System.IO.Path.GetFileNameWithoutExtension(txtPowerPoint.Text);

                    COM.Web myWeb = myContexto.Web;

                    COM.List myLista = myWeb.Lists.GetByTitle(txtNombreLista.Text);

                    COM.Folder myCarpeta = myWeb.GetFolderByServerRelativeUrl(txtNombreLista.Text + "/" + NombreCarpeta);

                    COM.FileCreationInformation fileCreationInfo = new COM.FileCreationInformation();

                    fileCreationInfo.Content = DiaFigura;

                    fileCreationInfo.Url = txtUrlSitio.Text + "/" + txtNombreLista.Text + "/" +

                                           NombreCarpeta + "/dia-" + DiaNumero.ToString() +

                                           "-fig-" + FiguraNumero.ToString() + ".jpg";

                    COM.File myFile = myCarpeta.Files.Add(fileCreationInfo);

                    myLista.Update();

                    myContexto.ExecuteQuery();

                }

            }

        }

Finalmente, eliminar la Biblioteca con el Modelo de Objetos de Cliente es también muy similar a como se hace con el Modelo de Objetos de Servidor:

        private void btnEliminarLista_Click(object sender, RoutedEventArgs e)

        {

            using (COM.ClientContext myContexto = new COM.ClientContext(txtUrlSitio.Text))

            {

                COM.Web myWeb = myContexto.Web;

                COM.List myLista = myWeb.Lists.GetByTitle(txtNombreLista.Text);

                myLista.DeleteObject();

                myContexto.ExecuteQuery();

                txtMensaje.Text += "Lista Eliminada\n";

            }

        }

Falta por mencionar una rutina auxiliar que concatena todos los elementos de cada LinkedList<string> en una sola cadena para el campo de “Contenido” de la Biblioteca:

        private Dictionary<int, string> DarTextoDocumentos(Dictionary<int, LinkedList<string>> todosLosTextos)

        {

            Dictionary<int, string> misTextos = new Dictionary<int, string>();

            foreach (KeyValuePair<int, LinkedList<string>> myTexto in todosLosTextos)

            {

                int DiaNumero = myTexto.Key;

                LinkedList<string> DiaTexto = myTexto.Value;

                string textoCompletoDia = string.Empty;

                foreach (string unTexto in DiaTexto)

                {

                    textoCompletoDia += unTexto + " - ";

                }

                misTextos.Add(DiaNumero, textoCompletoDia);

            }

            return misTextos;

        }

El resultado en SharePoint se puede ver en la Figura 3, en donde se ha utilizado una presentación de PowerPoint con tres diapositivas, en donde en la última se encuentra una imagen.

Para crear una rutina de despliegue para distribuir el programa es necesario distribuir también los ensamblados de OpenXML y del Cliente de SharePoint. Desde Visual Studio 2010, en el Explorador de Soluciones abra la sección de Referencias, seleccione DocumentFormat.OpenXml, Microsoft.SharePoint.Client y Microsoft.SharePoint.Client.Runtime (mantenga el botón de control para seleccionarlos al tiempo) y utilizando el botón derecho del ratón seleccione “Propiedades” y en la opción de “Copia local” escoja “Si”; esto incluye los tres dlls en el paquete de distribución. Visual Studio se encarga de empacar todos los archivos necesario para poder distribuir el programa: desde el Explorador de Soluciones seleccione el proyecto y utilizando el botón derecho del ratón escoja “Publicar”; siga las instrucciones para publicar la solución como una instalación de CD-ROM en un directorio local o remoto. El paquete de instalación incluye el programa propiamente dicho y los tres ensamblados empacados en archivos .deploy especial que los instala en el GAC del computador local que va a ejecutarlo.

Conclusión

El Modelo de Objetos de Cliente de SharePoint 2010 libera a los desarrolladores de las limitaciones de los Servicios Web, permitiendo programar aplicaciones de cliente de una forma mucho más sencilla, utilizando un paradigma Orientado a Objetos y con una sintaxis muy parecida a la utilizada en el Modelo de Objetos de Servidor. OpenXML ofrece la posibilidad de trabajar con documentos de Office programáticamente: abrirlos, leer su contenido, modificarlo o crear nuevos documentos solo requiere algunas líneas de código. La combinación de ambos ofrece grandes posibilidades para permitir que usuarios de SharePoint utilicen el sistema en formas nuevas e innovativas.

En cuanto a programación, tenga en cuenta que:

-          Es necesario instalar el OpenXML SDK en el computador de desarrollo

-          Si no se está desarrollando en un computador que tiene instalado SharePoint, es necesario copiar los dlls Microsoft.SharePoint.Client.dll y Microsoft.SharePoint.Client.Runtime.dll localmente desde un servidor de SharePoint (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\)

Finalmente, en cuanto a distribución del programa para despliegue, incluya los tres dlls (uno de OpenXML y dos del Modelo de Objetos de Cliente) en el mecanismo de publicación de Visual Studio, de tal forma que al ser utilizado el instalador se encargue de copiarlos al sitio correcto localmente.

 Descargar fuente

Sobre el autor

Gustavo Velez es ingeniero mecánico y electrónico especializado en el diseño, desarrollo e implementación de software basado en tecnologías de Microsoft, especialmente SharePoint (MVP MOSS). Es creador y web máster de http://www.gavd.net, sitio especializado en información en español sobre SharePoint y trabaja como Solutions Manager en Avanade Corp. (http://www.avanade.com).