Una de las grandes ventajas que nos dan las FarmSolutions es que nos permiten extender los WebParts implementados por el propio equipo de producto. En versiones anteriores (2007 y 2010) era común extender el funcionamiento de WebParts como el OWA, o el clásico Content Query.
En la versión 2013 el WebPart más utilizado por todos es el Content By Search. Su funcionamiento, tal y como indica su nombre, muestra el contenido de la búsqueda. Además, podemos diseñar diversas plantillas para mostrar datos de acuerdo a nuestras necesidades.
Ahora bien, hay algunos casos en los que la funcionalidad de serie se queda corta. ¿Cómo podemos solucionarlo? Pues extendiendo el componente y agregándole nuestra funcionalidad. ¿Lo vemos?
Caso de uso
Tenemos una Intranet en la que el departamento de Comunicación va publicando diversas noticias. Estas noticias están clasificadas dependiendo de la audiencia a la que va dirigida.
Partamos del caso que en nuestra organización tenemos los siguientes bloques: Negocio, RSC, Recursos Humanos, etc. Cada bloque contiene una temática diferente, pero se crean desde el mismo lugar.
¿Cómo lo hacemos?
Está claro que SharePoint es la mejor plataforma empresarial para tener la Intranet corporativa, ¿no? Ahora bien, utilizando la infraestructura de publicación que hay en SharePoint junto con el servicio de búsqueda, podemos gestionar el contenido de las noticias.
Pero… ¿Cómo podemos hacer para que en cada bloque aparezca las noticias de su área ? Podemos aprovechar la buena gestión de grupos del Active Directory (AD) y de SharePoint. Esta buena gestión pasa por sacarle partido a los grupos que tenemos en el AD. Por ejemplo, en casi todos los AD tenemos un grupo dependiendo del área de la organización. En SharePoint creamos un grupo por cada área y dentro de dicho grupo incluimos el grupo de AD. De esta forma evitamos tener el doble mantenimiento, cada vez que agregamos un miembro a nuestro grupo de AD se sincroniza con nuestro SharePoint.
Ahora que ya sabemos que podemos clasificar a una persona dependiendo del área a la que pertenece, tenemos que consultar y mostrar la información. Tenemos dos opciones:
- Hacer un desarrollo personalizado
- Extender el Out-of-the-box que viene por defecto en SharePoint
En nuestro caso, vamos a optar por la segunda opción por varias razones: la utilización de la infraestructura que viene de serie en SharePoint, displayTemplates, servicio de búsqueda, etc. Es preferible frente a plantear un desarrollo desde cero, que puede ser muy costoso y laborioso dependiendo de los requisitos a los que nos enfrentemos.
Extendiendo el WebPart
En primer lugar, nos crearemos una clase ExtendedCSWP que herede de la clase ContentBySearchWebPart que está dentro de la .dll Microsoft.Office.Server.Search.WebControls;
A continuación, en el método OnLoad de nuestro WebPart, agregamos un nuevo evento al método BeforeSerialiceToClient. Este evento lo que hace es crear la consulta sobre el servicio de búsqueda.
protected override void OnLoad(EventArgs e) { if (this.AppManager != null) { if (this.AppManager.QueryGroups.ContainsKey(this.QueryGroupName) && this.AppManager.QueryGroups[this.QueryGroupName].DataProvider != null) { this.AppManager.QueryGroups[this.QueryGroupName].DataProvider.BeforeSerializeToClient += new BeforeSerializeToClientEventHandler(UpdateQueryText); } } base.OnLoad(e); }
Dentro de este evento, tenemos que añadir la funcionalidad que queremos hacer. En nuestro caso, lo que vamos a realizar es la consulta predefinida. Le agregaremos que filtre por los grupos a los que pertenece el usuario, de tal forma que en el Template solamente se mostrarán las noticias que estén vinculadas a la temática que pertenece el usuario:
private void UpdateQueryText(object sender, BeforeSerializeToClientEventArgs e) { DataProviderScriptWebPart dataProvider = sender as DataProviderScriptWebPart; string currentQueryText = dataProvider.QueryTemplate; var taQuery = BuildTAQuery(); if (!isInit) { dataProvider.QueryTemplate = string.Concat(currentQueryText, " ", taQuery); Logger.Info("ExtendedCSWP Complete Query: " + dataProvider.QueryTemplate); isInit = true; } } private string BuildTAQuery() { string query = string.Empty; if (this.FieldName != null && !string.IsNullOrWhiteSpace(this.FieldName)) { using (SPSite site = new SPSite(SPContext.Current.Web.Url)) using (SPWeb web = site.OpenWeb()) { SPUser currentUser = web.CurrentUser; Logger.Info("ExtendedCSWP UserName: " + currentUser.Name); SPGroupCollection grpColl = currentUser.Groups; var sb = new StringBuilder(); if (grpColl.Count > 0) { foreach (SPGroup grp in grpColl) { Logger.Info("ExtendedCSWP GroupName: " + grp.Name); sb.Append(this.FieldName); if (!this.FieldName.Contains("OWS")) sb.Append("OWSUSER"); sb.Append(":\""); sb.Append(grp.Name); sb.Append("\" OR "); } query = sb.ToString(0, sb.Length - 4); } } } return query; }
¡Una aclaración! El servicio de búsqueda está claro que filtra dependiendo de los permisos que el usuario tenga. En nuestro caso, lo que estamos haciendo es mostrar el contenido según la temática del usuario que está logado y no dependiendo de los permisos que uno tenga.
Entre otras cosas, una mala gestión sobre los permisos puede provocar una lentitud en nuestro sistema. Además, si un usuario no tiene permisos sobre una noticia por mucho que pertenezca al grupo sobre el que se está buscando, el usuario no la visualiza.
Por último, en nuestro caso hemos añadido una propiedad dentro del ToolPart, de tal forma que podamos utilizar este WebPart en más escenarios.
Conclusión
A veces escuchamos que las Farm Solutions no son soluciones que debamos utilizar, principalmente porque en manos inexpertas pueden hacer que nuestra granja tenga problemas de rendimiento, ahora bien, no utilizarlas impide que se extienda el funcionamiento de algunos artefactos de una forma sencilla.
En este artículo, como en muchas ocasiones, te he hablado del modelo de extender SharePoint que propone Microsoft (plantea que apostemos por la creación de soluciones que no estén alojadas en SharePoint). Este modelo está pensando naturalmente en el Cloud, pero está claro que hay entornos OnPremise y en estos entornos tenemos algún escenario que no es posible utilizarlos en la nube pero no por ello es menos valido o útil.