Uno de los puntos más importantes en el desarrollo de aplicaciones para SharePoint 2010 es sin duda el desarrollo de Web Parts, por lo que en esta ocasión, vamos a aprovechar para crear un breve artículo de introducción, que sin mayor ambición, pueda servir de ayuda o de recordatorio a muchos de nosotros.
Introdución a las Web Parts en SharePoint 2010
Las Web Parts son controles ASP.NET del lado del Servidor que se ejecutan bajo el contexto de un Página de Web Parts (Web Part Page), las cuales tienen Zonas de Web Parts (Web Part Zones) que actúan como contenedores (Placeholders) y permiten a los usuarios editar y modificar los controles utilizando el navegador.
Dado que las Web Parts se ejecutan bajo el contexto de una página y bajo el contexto de seguridad del usuario que accede a la página, la misma Web Part puede mostrar distinta información en función del usuario que accede a la página, incluso accediendo a diferentes orígenes de datos externos (ej: Reporting Services, Analysis Services, etc) sin tener que volver a introducir las credenciales.
Cada página de Web Parts tiene:
- Zonas de Web Parts (Web Part Zones), que son contenedores de controles que pueden hospedar ninguna, uno o varias Web Parts.
- Web part manager, un objeto que lleva un registro de qué Web Parts han sido añadidas a cada Zona de Web Parts, y almacena información sobre cómo ha sido personalizada cada Web Part.
Podemos decir que SharePoint 2010 soporta dos tipos de Web Parts:
- ASP.NET 2.0 Web Parts, que derivan de System.Web.UI.WebControls.WebParts.WebPart. Utilizan directamente las clases el ASP.NET WebPartManager y WebPartZones. Como regla general, siempre deberemos crear este tipo de Web Parts.
- SharePoint web parts, que derivan de Microsoft.SharePoint.WebPartPages.WebPart. Utilizan las clases SPWebPartManager y SPWebPartZone, que heredan de las correspondientes clases de ASP.NET. Son proporcionadas con propósitos de compatibilidad hacia atrás y para algún caso excepcional. No está recomendado heredar de estas clases, excepto bajo ciertas circunstancias (ej: cross page connections, comunicación de web parts entre zonas, etc.).
Visual Web Parts para Soluciones de Granja (Farm Solutions)
Antes de continuar, es interesante recordar que en el pasado, no había una forma visual o gráfica de desarrollar Web Parts con Visual Studio, por lo que algunos desarrolladores creaban controles ASP.NET (es decir, ASP.NET Web User Controls, ficheros *.ascx) de forma visual con Visual Studio, para seguidamente construir un wrapper para utilizar los controles ASCX desde una Web Part, o bien utilizar un Wrapper existente como el conocido SmartPart for SharePoint (AKA Return of SmartPart).
Afortunadamente, con SharePoint 2010 todo esto es mucho más fácil, ya que Visual Studio 2010 introduce diseñadores gráficos para desarrollar Web Parts. Es decir, en un Proyecto de Visual Studio 2010 para SharePoint 2010, podremos agregar un nuevo Item de tipo Visual Web Part.
Realmente, lo que Visual Studio 2010 va a hacer por nosotros, es crear un ASP.NET Web User Control (*.ascx) sobre el cual tendremos la posibilidad de desarrollar de forma gráfica (añadir controles con el ratón, etc.) a la vez que creará automáticamente un Wrapper (en nuestro caso de ejemplo, la clase TestVisualWebPart) que heredará de la clase WebPart, por lo que no es necesario utilizar el SmartPart ni hacernos nosotros uno propio. Vamos, que una Visual Web Part es simplemente una Web Part que hospeda a un ASP.NET User Control.
Visual Studio desplegará el ASP.NET Web User Control por debajo de la carpeta 14 hive, tal y como se muestra en la siguiente pantalla capturada, por lo tanto una Visual Web Part sólo puede utilizarse en una Solución de tipo Granja (es decir, no es posible en una Solución Sandbox).
Visual Studio también nos creará una clase (en nuestro caso de ejemplo es el fichero TestVisualWebPart.cs), que heredará de System.Web.UI.WebControls.WebParts.WebPart. Esta es realmente nuestra Web Part, y en ella se sobrescribe el método CreateChildControls para cargar el ASP.NET Web User Control.
Igualmente, Visual Studio también nos creará un fichero *.webpart, en el cual podremos especificar información como el nombre y descripción de nuestra Web Part.
En términos generales, podríamos decir que el desarrollo de una Visual Web Part es como el desarrollo de un ASP.NET Web User Control, es decir, ahora podemos dibujar nuestros controles con el diseñador, añadir los eventos que deseemos (ej: el OnClick de un botón), etc. Francamente sencillo.
Soluciones de Granja (Farm Solutions), Web Parts y Controles Seguros (Safe Controls)
Cuando desarrollamos una Web Part para desplegarla a nivel de Granja, necesitamos marcarla como un Control Seguro (Safe Control), es decir, debemos modificar el fichero Web.Config de la Aplicación Web de SharePoint en la que deseamos utilizar la Web Part, para añadir una entrada de tipo SafeControl. Afortunadamente, Visual Studio 2010 hace este trabajo por nosotros. Si seleccionamos nuestra Web Part en nuestra Solución de Visual Studio, y mostramos sus Propiedades (F4), podremos acceder a la opción Safe Control Entries.
Dentro de la opción Safe Control Entries, podremos ver que ya aparece una entrada correspondiente a nuestra Web Part, sin que nosotros tuviésemos que hacer nada especial previamente.
Además, si desplegamos nuestra Solución de Visual Studio, y tras esto editamos el fichero Web.Config, podremos ver que se ha añadido dicha línea al Web.Config.
De hecho, si eliminamos dicha línea del Web.Config e intentamos utilizar nuestra Web Part, obtendremos un error como el siguiente:
Utilizar configuraciones del Web.Config: secciones appSettings y connectionStrings
Una forma bastante habitual de guardar configuraciones en aplicaciones de SharePoint, ya sea para ser utilizadas por Web Parts o bien por otros elementos que estemos desarrollando, es utilizando el fichero Web.Config, de forma similar a como se haría con cualquier otra aplicación ASP.NET. Esto tiene varias consideraciones:
- Al modificar el fichero Web.Config, se descargará de memoria el App Pool, lo cual en algunas Granjas de SharePoint puede implicar que se produzca una indisponibilidad, más o menos prolongada en el tiempo.
- Una Aplicación Web tiene un único Web.Config, por lo tanto, si tenemos varios Sites y necesitamos un valor de configuración diferente para cada Site, deberemos guardar una variable distinta en el Web.Config para cada Site, o bien, descartar el Web.Config y buscar otra alternativa para almacenar nuestras configuraciones.
- El fichero Web.Config es un fichero XML, por lo que deberemos almacenar cifrada cualquier información sensible, como cadenas de conexión, usuarios y contraseñas, etc, evitando de este modo introducir nosotros mismos una vulnerabilidad en nuestros sistemas.
- En las Soluciones Sandboxed no tenemos acceso al Web.Config, por lo que deberemos buscar otra alternativa para almacenar nuestras configuraciones.
Lo más común, es utilizar las secciones appSettings y/o connectionsStrings del Web.Config, aunque hay más formas de utilizar el Web.Config. En resumidas cuentas:
- La sección appSettings (configuration -> appSettings) permite almacenar parejas de clave/valor, permitiendo almacenar cualquier configuración que deseemos.
- La sección connectionStrings (configuration -> connectionStrings) se introdujo en .Net Framework 2.0 con la intención de ser utilizado únicamente para almacenar cadenas de conexión en el Web.Config, a diferencia de la sección appSettings que resulta mucho más general.
A continuación se muestra un ejemplo de uso de dichas secciones en un Web.Config:
Para poder consultar la sección connectionStrings desde el código fuente de nuestra Web Part, deberemos añadir una referencia al assembly System.Configuration (Project > Add Reference > Add System.Configuration). Además, es también recomendable importar los tipos definidos en el espacio de nombres System.Web.Configuration (ej: using System.Web.Configuration). Realizado esto, podremos consultar las secciones appSettings y connectionSettings utilizando la clase WebConfigurationManager (disponible desde .Net Framework 2.0), tal y como se muestra en el siguiente ejemplo:
En esto ejemplo, conseguiremos mostrar en dos etiquetas de una Web Part, el contenido de ambas configuraciones del Web.Config, tal y como podemos ver a continuación:
Otro tema a tratar es cómo modificar el Web.Config desde una Solución de Visual Studio, de tal modo, que podamos añadir al Web.Config las configuraciones que necesitan nuestras Web Parts antes de que las utilicen, evitando tener que realizar manualmente dichas modificaciones del Web.Config. Una forma de conseguirlo es por código, a través de un Event Receiver que se ejecute al Activar una Característica (FeatureActivated). De este modo, utilizando la colección WebConfigModifications, podemos añadir las modificaciones que deseamos realizar sobre el Web.Config, para seguidamente aplicarlas, es decir, que tomen efecto. Sería un trozo de código parecido al siguiente (ojo, la propiedad Owner es texto libre, podemos poner lo que queramos, y sirve que podamos hacer un tracking de nuestras modificaciones, frente a las modificaciones de otras aplicaciones):
Hay un tema importante. El contenido de la colección WebConfigModifications es persistente y se almacena en la Base de Datos de Configuración, por lo tanto, cada vez que activemos la característica, estaremos añadiendo una nueva entrada a esta colección. Esto nos puede generar valores repetidos. He visto casos de varios miles en entornos de producción de clientes reales.
Por ello, deberemos preocuparnos de eliminar nuestras entradas del Web.Config, del mismo modo que nos preocupamos de añadirlas. Por ejemplo, podemos utilizar un Event Receiver que se ejecute al desactivar la Característica (FeatureDeactivating), para eliminar de la colección WebConfigModifications las entradas del Web.Config que ya no necesitamos. Esto lo podíamos hacer con un código como el siguiente, pero ojo, ya que es posible que nos encontremos con el error de Access Denied al intentar modificar el Web.Config desde SharePoint 2010.
Antes de continuar con el resto del artículo, aprovecho para colgar varios enlaces de interés, para quien desee ampliar más información:
Crear Propiedades en una Visual Web Part
Las Propiedades de las Web Parts, son una de las principales formas que tenemos para poder personalizarlas, ya que de este modo, podemos permitir que los usuarios puedan editar dichas Propiedades y asignarles los valores que deseen, que nuestra Web Part podrá utilizar a nuestro antojo.
Para poder crear una Propiedad en nuestra Web Part, deberemos crear una propiedad pública en la clase de la Web Part con ciertos atributos (Personalizable, WebBrowsable, WebDisplayName, WebDescription, Category). Realizado esto, el problema es cómo poder utilizar el valor de esta propiedad definida en la Web Part desde el ASP.NET Web User Control, dado que se trata de dos clases independientes. Una forma de solucionar esta situación, es creando una nueva propiedad pública en el ASP.NET Web User Control y asignarle el valor deseado en su creación dentro del método CreateChildControls.
Esto implica que el código de nuestra Web Part (TestVisualWebPart.cs) quedaría algo como lo que se muestra en la siguiente pantalla capturada.
Del mismo modo, el código de nuestro ASP.NET Web User Control (TestVisualWebPartUserControl.ascx.cs) quedaría algo como lo que se muestra en la siguiente pantalla capturada.
Realizado todo esto, si desplegamos ahora nuestra Web Part, al editarla podremos observar la nueva propiedad que acabamos de crear.
WebBrowsable vs Personalizable
Los atributos WebBrowsable y Personalizable, generan ciertas dudas en su uso, tratándose de dos atributos bien diferenciados:
- WebBrowsable. Permite que la propiedad pueda ser editada por los usuarios, apareciendo en el Toolbox. Sin embargo, no hace nada en relación con la persistencia de su valor.
- Personalizable. Permite que el valor de la propiedad debe ser persistente.
Aunque ambos atributos suelen usarse juntos en muchos casos, es posible también usarlos de forma completamente independiente.
Conexiones entre Web Parts
Cabe la posibilidad de conectar un par de Web Parts, de tal modo, que una de ellas actúe como el Proveedor de Datos y la otra como el Consumidor de Datos, formando una relación Padre-Hijo ó Maestro-Detalle entre ellas. Es decir, al seleccionar un elemento en el Web Part que actúa como Padre o Maestro, podremos filtrar automáticamente el contenido de la Web Part Hijo o Detalle.
Esta funcionalidad sólo está disponible en Soluciones de Granja, es decir, no la tenemos en Soluciones Sandboxed, por lo que podemos utilizar Visual Web Parts o las Web Parts tradicionales (sin diseñador gráfico ni ASP.Net User Control), como deseemos.
Por lo que he leído (yo no llego a estos detalles), hay dos tipos de conexiones que pueden ser utilizadas entre las Web Parts:
- Conexiones Estáticas. Requiere codificar una Web Part no-ASP.Net, es decir, que derive de la clase Microsoft.SharePoint.WebPartPages.WebPart. Su caso de uso típico es cuando al menos una de las Web Parts no reside en una Web Part Zone, algo que quizás no es muy habitual pero que podría ocurrir, o también cuando se desea establecer la información de la conexión entre ambas Web Parts en el código HTML/html de la Página.
- Conexiones Dinámicas. Pueden ser codificadas con Web Parts ASP.Net, y en este caso, ambas Web Parts residen en alguna Web Part Zone. Quizás es el caso más habitual, en el cual, un usuario puede de forma gráfica editar una Web Part y conectarla con otra Web Part, de forma dinámica.
A continuación, vamos a presentar un ejemplo del desarrollo de un par de Web Parts ASP.Net conectables entre sí, en particular de un par de Visual Web Parts, con sus correspondientes ASP.Net User Controls.
Lo primero que deberemos crear es una Interfaz (IMasterProvider) con una Propiedad de sólo lectura (MasterID), que será implementada por el Proveedor de Datos (la Web Part que actúa como Padre o Master) y usada por el Consumidor de Datos (la Web Part que actúa como Hijo o Detalle).
Seguidamente deberemos crear una Visual Web Part que actúe como Web Part Padre o Master (VisualMasterWP), el Proveedor de Datos. Esta Web Part debe implementar la anterior Interfaz (IMasterProvider). Contiene el correspondiente ASP.Net User Control (VisualMasterWPUserControl), con un DropDownList configurado con la propiedad AutoPostBack a True. Otro detalle, es que la clase de la Web Part (VisualMasterWP) debe incluir un método que devuelve el anterior Interfaz (y en su interior un simple return this) etiquetado con la propiedad/atributo ConnectionProvider, para que SharePoint detecte el rol de esta Web Part en la conexión, especificando como parámetro el texto que queremos que muestre SharePoint en la Conexión (ver más abajo, el pantallazo cuando probamos las Web Parts). En consecuencia, el código de la Web Part (VisualMasterWP) quedaría algo así.
Del mismo modo, el código del ASP.Net User Control de la Web Part (VisualMasterWPUserControl) quedaría algo así.
Una Visual Web Part que actúe como Web Part Hijo o Detalle (VisualDetailWP), el Consumidor de Datos. Esta Web Part debe usar la anterior Interfaz (IMasterProvider). Contiene el correspondiente ASP.Net User Control (VisualDetailWPUserControl), con una etiqueta (Label) en la que actualizar su contenido en función del valor seleccionado en el Combo de la Web Part que actúa como Padre. La clase de la Web Part (VisualDetailWP) debe incluir un método que espera como parámetro un objeto que implemente la anterior Interfaz (IMasterProvider) etiquetado con la propiedad/atributo ConnectionConsumer, para que SharePoint detecte el rol de esta Web Part en la conexión, especificando como parámetro el texto que queremos que muestre SharePoint en la Conexión (ver más abajo, el pantallazo cuando probamos las Web Parts). Este es el mecanismo para intercambiar información entre ambas Web Parts, junto con el evento OnPreRender de la Web Part (este método se ejecuta después del método CreateChildControls), que sobrescribiremos para conseguir actualizar el valor de la Etiqueta (Label) de nuestra Web Part Hijo. En consecuencia, el código de la Web Part (VisualDetailWP) quedaría algo así.
Del mismo modo, el código del ASP.Net User Control de la Web Part (VisualDetailWPUserControl) quedaría algo así.
Realizado todo esto, estaremos en situación de compilar y desplegar nuestra Solución de Visual Studio en nuestra Granja de SharePoint 2010, para a continuación añadir ambas Web Parts a una Página de SharePoint, y conectarlas.
Una vez conectadas ambas Web Parts, podremos comprobar su funcionamiento. En nuestro caso de ejemplo, al seleccionar un elemento en el Combo de la Web Part que actúa como Padre o Master (VisualMasterWP), se actualizará el contenido de la etiqueta que tenemos en la Web Part que actúa como Hijo o Detalle (VisualDetailWP).
Las Visual Web Parts y las Soluciones Sandbox (Sandboxed Solutions)
Como acabamos de ver, una Visual Web Part no la podremos utilizar en una Solución Sandbox. Por lo tanto, si tenemos una Solución Sandbox y necesitamos añadir una Web Part ¿qué podemos hacer? En este caso, podemos utilizar Web Parts de sólo código (Code-Only Web Part), que si bien no ofrece la comodidad de un diseñador gráfico (tendremos que hacerlo todo por código, ya que en esta ocasión no tenemos un ASP.NET Web User Control embebido en la Web Part), por el contrario, podremos incluirla en una Solución Sandbox. De hecho, una Code-Only Web Part la podremos utilizar tanto en una Farm Solution como en una Sandboxed Solution.
Una Solución Sandbox (Sandboxed Solution) se ejecuta en un proceso aislado, por lo tanto, utilizando este tipo de Soluciones en lugar de las antiguas Soluciones de Granja (Farm Solutions), la Granja de SharePoint está expuesta a un menor riesgo, y además son compatibles con SharePoint OnLine (Office 365). Sin embargo, las Soluciones Sandbox (Sandboxed Solutions) tienen algunas limitaciones, como por ejemplo:
- Las llamadas a Servicios Web (Web Services) no están soportadas.
- No están disponibles todos los objetos, propiedades y métodos disponibles en el modelo de objetos. El IntelliSense puede ayudarnos ocultarnos los objetos, propiedades y métodos no disponibles, pero en cualquier caso, Visual Studio no lo comprobará hasta en tiempo de ejecución.
- Sólo está permitido el acceso a los objetos SharePoint del mismo Site en el que está ejecutándose la Solución Sandboxed.
No obstante, existen algunas soluciones de terceros, que nos pueden facilitar el desarrollo visual de las Web Parts. Por ejemplo, podemos utilizar las Visual Studio 2010 SharePoint Power Tools disponible de forma gratuita en CodePlex, que nos añadirá una nueva Plantilla a Visual Studio 2010 denominada Visual Web Part (Sandboxed).
Web Parts de sólo código para Soluciones Sandbox (Sandboxed Solutions)
En este caso, al crear una Web Part de sólo código, no tendremos un ASP.NET Web User Control, por lo tanto, aunque igualmente deberemos sobrescribir el método CreateChildControls (ojo, aunque también sería posible sobrescribir los métodos Render y RenderContents, como norma general deberemos evitar utilizarlos), en esta ocasión utilizaremos dicho método para crear por código los Controles que deseamos que tenga nuestra Web Part, así como sus Eventos (Event Handlers).
Además, para los Eventos (Event Handlers) deberemos crear los correspondientes métodos capaces de responder a dichos eventos con el comportamiento que deseamos. Téngase en cuenta que podemos utilizar la colección Controls para acceder a los Controles de nuestra Web Part, y de este modo, obtener el valor de la propiedad Text de nuestras cajas de texto (TextBox), o lo que necesitemos. Igualmente, podemos ejecutar consultas CAML, y muchas cosas más.
Realizada esta codificación, podremos desplegar nuestra Web Part, y comprobar su funcionamiento.
Despliegue de las Web Parts en SharePoint 2010
Tenemos diferentes opciones para realizar el despliegue de las Web Parts en SharePoint 2010, las cuales pueden variar en función del tipo de Solución que estemos desarrollando (Sandboxed ó Farm).
Para las Soluciones Sandboxed deberemos subir nuestra solución a la Galería de Soluciones (Solution Gallery) de la Colección de Sitios en la que desees utilizarla.
Para las Soluciones de Granja (Farm Solutions) podremos realizar el despliegue en dos ubicaciones distintas, lo cual, el relevante sobre el nivel de permisos bajo el que se ejecutará el assembly (DLL) y también indicará si se desplegará sobre toda la Granja o sobre un Aplicación Web en particular. Entrando en un poco más de detalle:
- Global Assembly Cache (GAC). Es la opción por defecto en Visual Studio 2010. Al realizar el despliegue de este modo, la Solución estará disponible para todas las Aplicaciones Web de la Granja de SharePoint, ya que la DLL de la Solución será desplegada en la GAC, y por lo tanto, se ejecutará en modo Full Trust (algunas empresas no permiten que se desplieguen DLLs en la GAC, por motivos de seguridad).
- Directorio BIN de la Aplicación Web. De este modo podemos realizar el despliegue sólo en las Aplicaciones Web en las que activemos la Característica (Feature) de nuestra Web Part, de tal modo, que la DLL será desplegada únicacamente a la Aplicación Web que deseemos, y además, por defecto se ejecutará en modo Minimal Trust (WSS_Minimal).
Muy importante tener en cuenta las políticas de CAS (Code Access Security), es decir, el nivel de permisos bajo el que se ejecuta un assembly, o dicho de otro modo, qué es lo que puede o no hacer nuestra Web Part. Por defecto, el Web.Config de una Aplicación Web de SharePoint indica que todo el código se debe ejecutar en modo Minimal Trust (WSS_Minimal) excepto los assemblies desplegados en la GAC (que se ejecutarán en modo Full Trust, es decir, barra libre de permisos). Este comportamiento se puede cambiar modificando el Web.Config. Recordemos que ASP.Net define los modos Full, High, Medium, Low y Minimal, a lo que SharePoint añade otros dos modos más: WSS_Minimal y WSS_Medium. Para más info, puede resultar interesante consultar el siguiente post de Luis Mañez (muy bueno): Trust Levels en ASP.NET y Sharepoint. También sería posible crear un nivel personalizado (ver Code Access Security in SharePoint), aunque es bastante habitual configurar el Web Config para utilizar el modo Full Trust (incluso aunque no sea la opción más recomendable).
Es en las Propiedades de nuestro Proyecto de Visual Studio 2010, donde podremos cambiar las opciones de despliegue de nuestra Solución.
Despedida y Cierre
Hasta aquí llega el presente artículo, en el cual, hemos intentado realizar una introducción general del desarrollo de Web Parts para SharePoint 2010 con Visual Studio 2010, sin duda, una de las tareas más relevantes en el desarrollo de aplicaciones para SharePoint.
Por último, antes de acabar, tan sólo queda colgar un poco de código fuente para quien desee probarlo por sí mismo con Visual Studio 2010.
Poco más por hoy. Como siempre, confío que la lectura resulte de interés.