HttpModule en Sharepoint 2007

El otro día nos encontramos frente a un requerimiento que nos solicito un cliente. El necesitaba listar los documentos más vistos de una colección de sitios y todos los sub sitios por debajo de dicha colección de sitio.

Sharepoint posee una característica llamada “Auditoria de la información”  la cual una vez habilitada y configurara en el sitio correspondiente registra todos los eventos que se producen en toda la colección de sitios. Se puede registrar los ítem vistos, los ítem modificados, etc. En definitiva se auditan todos los eventos que se producen en nuestro portal Sharepoint 2007, próximamente vamos a estar compartiendo con Uds. un artículo al respecto, dado que dicha característica es muy útil.

Pero para este caso en particular nosotros tomamos la decisión de realizar un modulo que atrapara la URL del request y procesara si se trataba de un documento o de simplemente una página.

Este modulo implementa la interface IHttpModule de Asp.Net, nos permite registrarnos a eventos durante todo el proceso de solicitud que se está realizando en nuestro portal Sharepoint 2007.

Durante una solicitud (Request) a una página de nuestro portal durante todo el proceso del mismo se desencadenan varios eventos a los cuales nosotros nos podemos registrar. Estos eventos tienen un orden lo cual nos permite codificar algún comportamiento adicional en determinado momento. En la sección 1 vemos la lista de eventos proporcionada por la clase SPHttpApplication la cual usamos para registrarnos a los mismos. Cabe la pena destacar que dicha clase extiende de HttpApplication de Asp.Net e incorpora algunas propiedades y métodos adicionales, por mas información dirigirse a la pagina del MSDN.

 

Sección 1

·         AcquireRequestState

·         AuthenticateRequest

·         AuthorizeRequest

·         BeginRequest

·         Disposed

·         EndRequest

·         Error

·         PostAcquireRequestState

·         PostAuthenticateRequest

·         PostAuthorizeRequest

·         PostMapRequestHandler

·         PostReleaseRequestState

·         PostRequestHandlerExecute

·         PostResolveRequestCache

·         PostUpdateRequestCache

·         PreRequestHandlerExecute

·         PreSendRequestContent

·         PreSendRequestHeaders

·         ReleaseRequestState

·         ResolveRequestCache

·         UpdateRequestCache

 

 

Vale la pena destacar que si queremos acceder al modelo de objeto del portal en ejecución mediante la clase SPContext nos deberíamos registrar a cualquier evento después del evento “PostAuthenticateRequest” dado que recién después del mismo estamos autenticándoos y tendremos acceso al contexto de ejecución.

En la sección 2 vemos el código necesario para la creación de nuestro HttpModule utilizando Visual Studio 2005 y en el cual nos registramos a dos eventos “BeginRequest” y “PostRequestHandlerExecute”. En el primero no contamos con acceso al contexto de ejecución, si quisiéramos acceder a al sitio en ejecución obtendríamos un error indicando que el objeto no está listo, pero sí en cambio lo hacemos en el segundo evento, como el proceso de autorización se produjo no tendremos problema en acceder al sito en ejecución.

 

Sección 2

 

using System;

using System.Collections.Generic;

using System.Text;

using System.Web;

using Microsoft.SharePoint;

using Microsoft.SharePoint.ApplicationRuntime;

 

namespace Siderys.HttpModuleBlog

{

    public class HttpModuleSharepoint : IHttpModule

    {

        public void Init(HttpApplication app)

        {

            SPHttpApplication spApp = (SPHttpApplication)app;

            spApp.BeginRequest += new EventHandler(BeginRequestHttpModuleBlog);

            spApp.PreRequestHandlerExecute += new EventHandler(PreRequestHandlerExecuteHttpModuleBlog);

        }

 

        void BeginRequestHttpModuleBlog(object sender, EventArgs e)

        {

            HttpContext.Current.Response.Write("HttModuleBlog <br>");  

        }

        public void PreRequestHandlerExecuteHttpModuleBlog(object sender, EventArgs e)

        {

            HttpContext.Current.Response.Write(SPContext.Current.Web.ToString());

        }

        public void Dispose()

        {

        }

 

    }

}

 

Una vez tenemos  programado nuestro HttpModule, lo que resta es registrarlo en el WebConfig del portal de Sharepoint, realizar un IISRESET para que el nuevo Assembly sea tenido en cuenta y realizar una petición al portal para que se ejecute nuestro HttpModule. En la sección 3 vemos el código necesario para agregar al Web.Config de nuestro portal Sharepoint.

 

Sección 3 

    <httpModules>

      <clear />

      . De más modulos

 <add name="HttpModuleBlog" type="Siderys.HttpModuleBlog.HttpModuleSharepoint, Siderys.HttpModuleBlog, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4b47d67002a80c61" />                    

    </httpModules>

En la imagen 1 vemos como lo que nosotros codificamos en el en el HttpModule se muestra  en la pagina solicitada. Es simplemente un ejemplo de lo que podemos realizar para solucionar algunos requerimientos.

 

Imagen 1

 httpModule

WebPart para Sharepoint 2007 usando UserControl

En el artículo anterior explicamos cómo usar el control de Sharepoint 2007 PeopleEditor y desarrollamos un formulario para colocarlo en Sharepoint.

En realidad lo que construimos fue una WebPart utilizando un UserControl la cual registramos en nuestro Sharepoint y utilizamos. Cuando necesitamos agregar funcionalidad adicional a nuestros sitios de Sharepoint recurrimos a la codificación mediante WebParts, las cuales nos permiten desarrollar dicho componente e incluirlo en nuestro portal Sharepoint. Pero todo sabemos que la codificación de una WebPart no es trabajo fácil y más cuando nos tenemos que preocupar de todo el dibujo (renderización de los controles incluidos en la misma) y el manejo de los preciados eventos, cuando la WebPart es sencilla no es tan complicado su desarrollo, pero ahora si lo que debemos codificar es un formulario complejo, el desarrollo de la misma no es nada trivial.

Nosotros vamos a desarrollar una WebPart, pero en vez de codificarla toda en la clase que implementa la clase base WebPart, lo vamos hacer mediante un UserControl de Asp.Net. Lo primero que tenemos que hacer es preparar nuestro ambiente en Visual Studio, para lo cual necesitamos 2 proyectos, un proyecto Web donde codificaremos el UserControl y un proyecto de Clases donde codificaremos nuestra WebPart, en la siguiente imagen se puede ver como quedaría nuestro ambiente:

Imagen 1

 1_Solucion_VisualStudio

Lo que debemos hacer ahora es configurar nuestros dos proyectos, para poder agregar la referencia al proyecto de biblioteca de clases. Ambos dos proyectos deben estar firmados con un Strong Name (archivo snk, si tienen uno en común  para todos sus desarrollos pueden utilizarlo, si no pueden generar uno con el Visual Studio), el primer proyecto que vamos a configurar es la biblioteca de clases y en las propiedades del proyecto vamos a colocar en archivo snk (Strong Name) en la sección correspondiente a firma del Visual Studio, como se puede ver en la imagen siguiente:

 

Imagen 2

 2_FirmaEnsamblado

Por último en la clase AssemblyInfo vamos agregar una elevación en los permisos de ejecución de nuestra WebPart para que la misma se ejecute sin ningún problema en nuestro portal de Sharepoint 2007, para eso agregamos el siguiente atributo en nuestro AssemblyInfo  [assembly: AllowPartiallyTrustedCallers()], en la siguiente imagen vemos como quedaría:

Imagen 3

3_AssemblyInfo

Una vez configurado nuestro proyecto de biblioteca, lo que demos hacer es configurar nuestro proyecto Web y crear el UserControl correspondiente, para lo cual vamos agregar un nuevo componente a dicho proyecto del tipo UserControl y lo vamos a grabar en el mismo. Una vez agregado lo que demos hacer es codificar el mismo según nuestras necesidades y requerimientos. En la imagen 4 vemos nuestro UserControl codificado, como nos estamos basando en el artículo anterior, nuestro UserControl simplente dibuja el control de Sharepoint PeopleEdito.

Imagen 4

4_UserControl_ASCX  

En la clase asociada a dicho UserControl vamos a codificar todo nuestro comportamiento para el mismo. Una vez que está terminado tenemos que publicarlo así podemos crear el Assembly necesario para dicho UserControl, para ello nos paramos sobre nuestro proyecto Web y seleccionamos publicar. En la nueva ventana que aparece en nuestro Visual Studio vamos a configurar como vamos hacer la publicación, debemos seleccionar una ruta donde se colocaran los archivos generados, vamos a indicarle que nos genere un Assembly independiente para cada uno de los archivos que tenemos en el proyecto Web y vamos a firmar los mismo con un Strong Name (el archivo snk  a utilizar puede ser el mismo que utilizamos para firmar la biblioteca de clases), la imagen 5 nos muestra como quedaría la pantalla configurada. 

Imagen 5

5_PublicacionUserControl  

Una vez publicado, vamos agregar la referencia al Assembly generado por el proceso de publicación en nuestro proyecto de clases, nuestro proyecto de clase debería quedar como se muestra en la siguiente imagen.

Imagen 6

6_Referencia_UserControl  

Los ultimo que vamos hacer es codificar nuestra WebPart para utilizar el UserControl utilizando el método LoadControl y pasándole una ruta a la ubicación de nuestro archivo ASCX, esta ruta deberá ser una ruta relativa en la raíz de nuestro portal Sharepoint, en nuestro caso colocamos el archivo ASCX en una carpeta llamada “UserControl” como se puede ver en la siguiente imagen. 

Imagen 7

7_UserControl_Folder 

En la siguiente sección entraremos el código necesario para cargar el UserControl en la WebPart y adicionarlo a la colección de controles. También hemos incorporado un manejo de errores que nos permitirá enviar el mensaje de error producido a la pantalla utilizada por Sharepoint 2007 para mostrar los mensajes de error.

 

Sección 1

 

using System;

using System.Runtime.InteropServices;

using System.Web.UI;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Serialization;

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;

using Microsoft.SharePoint.Utilities;

 

namespace PeopleEditorWebControlWebPart

{

    public class PeopleEditorWebControlWebPart : System.Web.UI.WebControls.WebParts.WebPart

    {

        private PeopleEditorWebControlUC mPeopleEditorWebControlUC = null;

        private Exception mError = null;

        private string mSourceQuery = string.Empty;

 

        public PeopleEditorWebControlWebPart()

        {

            this.ExportMode = WebPartExportMode.All;

        }

        protected override void CreateChildControls()

        {

            try

            {

                base.CreateChildControls();

                mPeopleEditorWebControlUC = (PeopleEditorWebControlUC)Page.LoadControl(@"/UserControl/PeopleEditorWebControlUC.ascx");

                Controls.Add(mPeopleEditorWebControlUC);

            }

            catch (Exception ex)

            {

                mError = ex;

            }

        }

        protected override void Render(HtmlTextWriter writer)

        {

            if (mError != null)

            {

                SPUtility.TransferToErrorPage(mError.Message + " —> " + mError.StackTrace);

            }

            base.Render(writer);

        }

    }

}

Por último nos queda compilar nuestra WebPart y registrarla en nuestro portal de Sharepoint para poder utilizarla, como cualquier otra Webpart.

Configuración Búsqueda Sharepoint 2007

 Manejando las propiedades del motor de búsqueda de Sharepoint 2007.

Cuando instalamos Sharepoint 2007 lo primero que tenemos que hacer es configurar el Shared Service Provaider (SSP), el cula nos brinda la posibilidad de contar con un conjunto de características centralizadas para todas las aplicaciones Web que nosotros relacionemos con este SSP. Dentro de estas características esta la del motor de búsqueda, el cual nos permite configurar todas las funcionalidades necesarias para crear índices a los contenidos cargados dentro de nuestros portales.

Lo que hace Sharepoint cada vez que el motor de búsqueda inicializa un rastreo es inspeccionar el sitio establecido, indexar el contenido y armar un índice para poder acceder a la información cuando realizamos una búsqueda desde cualquier sitio relacionado con este SSP.

 

Imagen 1

image

 

En la imagen 1 se puede ver la pagina central de la configuración de la búsqueda en el SSP y como se nota todavía no se tiene ningún elemento en el índice, puesto que en este SSP no se ha realizado un rastreo del contenido.

Para que Sharepoint pueda acceder al contenido de nuestro sitio el mismo debe estar configurado en la sección orígenes de contenido, en la siguiente imagen podemos ver como esta sección contiene un origen de contenido configurado por defecto. Pero nosotros podemos agregar cualquier origen de contenido.

 

 

Imagen 2

image

 

Como se muestra en la imagen 3 el origen de contenido puede estar dado desde un sitio de Sharepoint, un sitio web, archivos compartidos en la red, carpetas de Exchange y datos profesionales configurados.

Dependiendo de la opción que seleccionemos serán los valores que debemos establecer para el origen de contenido. También en esta pantalla podemos configurar cuando se realizara el rastreo del contenido, se puede configurar para que el mismo sea total o incremental.

 

 

Imagen 3

image

 

Una vez configurado el origen de datos, lo que tenemos que hacer es iniciar el rastreo del contenido, debemos indicarle que comience con el rastreo del contenido, para eso nos posicionamos sobre la opción de origen de datos y en él menú desplegable seleccionamos comenzar rastreo completo y con esto Sharepoint empezara a crear entradas en el índice. Además se adicionaran propiedades (meta datos) que originalmente no estaban en nuestro esquema de propiedades. Una vez terminado el rastreo la pantalla principal de configuración de la búsqueda debería verse como se muestra en la siguiente imagen:

 

Imagen 4

image

 

Una vez que tenemos creado el índice para nuestro motor de búsqueda, ahora vamos extender el esquema de propiedades de Sharepoint 2007 y agregaremos una propiedad nueva que la vamos a utilizar en la página de pagina de resultado extendiendo y modificando la misma utilizando XSLT para acceder al Schema “All_Results” devuelto por Sharepoint cada vez que buscamos en nuestro sitio.

Para poder crear una nueva propiedad debemos acceder a la sección “Asignaciones de propiedades de metadatos” dentro de la pantalla de configuración de la búsquedas.

 

En esta sección podemos ver todas las propiedades configuradas las propiedades existentes creadas por Sharepoint o podemos crear nuevas propiedades para que las mismas puedan ser incluidas en el índice cuando se vuelva a realizar un nuevo rastreo.

Estas propiedades pueden ser utilizadas para crear un ámbito de búsqueda (mas adelante veremos cómo crear el mismo), para ser adicionadas en el ComboBox de las búsquedas avanzadas o para ser utilizadas directamente en la página de resultados.  Las propiedades para que sean tenidas en cuenta deberán contener una asignación a las propiedades rastreadas por Sharepoint para que las mismas puedan ser utilizadas correctamente. La siguiente pantalla se utiliza para crea una nueva propiedad personalizada y también para editar una existente.

Imagen 5

image

 

Para crear una nueva propiedad seleccionamos el link “Nueva propiedad administrada” que se encuentra en la parte superior de la pantalla donde se nos abrirá una nueva ventana, ver imagen 6

Imagen 6

 image

 

En esta pantalla cargamos el nombre, descripción y qué tipo de dato será dicha propiedad administrada. También en esta pantalla es donde debemos realizar la asignación de la o las propiedades rastreadas por Sharepoint cuando se realizado el rastreo, para eso, seleccionamos el botón Agregar Asignación que se encuentra en la sección “Asignaciones a propiedades rastreadas”. Al presionar dicho botón se nos abrirá un PopUp como lo muestra la imagen 7 donde deberemos elegir que propiedad o propiedades rastreadas queremos asignar a la propiedad que estamos creando. Dependiendo del tipo de dato de la propiedad que estamos creando,  las propiedades rastreadas que se mostraran en cada una de las opciones cambiara  y solo nos mostrara las correspondientes al tipo de dato que estamos creando.

 

Imagen 7

image

 

En este ejemplo nosotros seleccionamos la propiedad rastreada llamada “ows_ID” del tipo entero, la cual nos permitirá obtener los IDs de los elementos devueltos por las búsquedas. Nuestra nueva propiedad debería quedar como se muestra en la siguiente imagen.

 

Imagen 8

image

 

Una vez nuestra propiedad está configurada la guardamos presionando el botón “Aceptar”. Por último comentar que si habilitamos el CheckBox que se encuentra en la sección “Uso en ámbitos” podremos usar esta propiedad para crear ámbitos de búsqueda contra esta propiedad en el sitio que nosotros querremos.

Vamos a establecer esta configuración en otra propiedad ya creada para después crear un ámbito de búsqueda utilizándola. Para ello seleccionamos la propiedad que queremos, en nuestro caso vamos habilitar la propiedad “Filename” para utilizarla en un ámbito de búsqueda, la pantalla se debe ver como lo muestra la siguiente imagen.

 

Imagen 9

image

 

Para que todas las modificaciones realizadas en la configuración de las búsquedas tengan efecto debemos realizar un nuevo rastreo, para lo cual vamos a la sección "Orígenes de contenido” que se encuentra en la pantalla principal de la configuración de las búsquedas y seleccionamos el origen que queremos que se comiencen con el rastreo, ver imagen 2 y comenzamos con el rastreo completo.

 

Página resultado búsqueda Sharepoint 2007

 Modificando página resultado de la búsqueda de Sharepoint (All_Results).

En el artículo anterior configuramos y extendimos las propiedades de la búsqueda de Sharepoint 2007 en el Shared Service Provider (SSP). Agregamos una nueva propiedad a los metadatos del motor de búsqueda llamada “IdElemento” y le asignamos una propiedad rastreada de Sharepoint llamada “ows_ID”. También extendimos la propiedad “Filename” permitiendo que la misma sea utilizada para crear un ámbito de búsqueda.

Lo que vamos a realizar ahora es extender la página de resultado adicionando la nueva propiedad creada, la cual nos permitirá generar un link al formulario de edición de un documento cargado en una biblioteca de documentos. Queremos lograr poder acceder a la página donde podemos editar las propiedades de un documento cargado, dado que cuando la página de resultado muestra un documento, solo provee un link para acceder al mismo.

En la imagen 1 vemos la página de resultado que Sharepoint nos muestra cuando realizamos una búsqueda dentro de nuestro sitio, como se puede ver, se listan todos los documentos cargados en el portal y los links en estos resultados nos brindan la posibilidad de abrir el mismo.

 Imagen 1

image

 

Lo primero que vamos hacer es configurar nuestra propiedad creada para que sea tenida en cuenta en el resultado de la pagina, para ello tendremos que acceder a la configuración de la WebPart editando la página.

Una vez editada la misma, vamos a modificar las columnas del Schema utilizada por la WebPart para mostrar el resultado y vamos agregar nuestra columna a dicha configuración, como se puede ver en la imagen 2, tenemos que acceder a la definición de las columnas.

Como podemos observar el editor de texto, es un editor simple  donde se muestran todas las columnas cargadas. Lo que podemos hacer es copiar todo el contenido y editarlo utilizando un editor XML, podemos usar Sharepoint Designer, Visual Studio o cualquier editor que nos permita trabajar con archivos XML. Nosotros vamos a utilizar Visual Studio para poder modificar y agregar la nueva columna. Como se puede ver en la imagen 3 hemos pegado el contenido del editor de texto de Sharepoint en un documento XML llamado “Columnas.XML” en el Visual Studio. 

 

Imagen 2

image

 

Imagen 3

image

 

Una vez que agregamos la nueva columna lo que debemos hacer es volver a colocar todo él contenido dentro de la definición de columnas de la WebPart utilizada para mostrar el resultado, ver imagen 2.

Lo que debemos hacer ahora es modificar el XSLT utilizado por la WebPart “CoreResultsWebPart” para mostrar el resultado de la búsqueda. Para realizar esta tarea podemos utilizar el Sharepoint Designer o el Visual Sudio.

En la figura 4 vemos como podemos editar el XSLT utilizando el Sharepoint Designer y modificar la pagina de resultado. El XSLT utilizado para mostrar los resultado está compuesto por varios template, nosotros vamos a modificar el template llamado “Result” que será invocado por cada ítem del resultado  de la búsqueda:
<xsl:template match="Result">………………… </xsl:template>

Imagen 4

image

 

Lo primero que tenemos que hacer es copiar el XSLT utilizado para poder editarlo y modificarlo, para lo cual tenemos que volver a editar la WebPart y acceder al XSLT, en la imagen 5 se puede ver cómo podemos realizar esta tarea.

Imagen 5

image

 

Una vez que tenemos copiado él XSLT lo pegamos en un documento XSLT en el Visual Studio para poder editarlo. Lo que vamos hacer es agregar un link al lado del título del documento para que nos permita editar las propiedades de cado uno.

Buscamos el temaplete llamado “Result” y colocamos el código necesario para construir el link. Dado que la ruta al formulario de la biblioteca de documento no nos es proporcionado por el resultado, lo que vamos hacer es construir dicho link utilizando una función JavaScript a la que le pasaremos la URL del documento y el ID proporcionado por nuestra propiedad.

A continuación vemos el código XSLT y la función JavaScript que vamos a colocar dentro del XSLT. En la figura 1 vemos el código del template modificado:

 

Figura 1

<xsl:template match="Result">
    <xsl:variable name="id" select="id"/>
    <xsl:variable name="url" select="url"/>
    <span class="srch-Icon">
        <a href="{$url}" id="{concat(‘CSR_IMG_’,$id)}" title="{$url}">
            <img align="absmiddle" src="{imageurl}" border="0" alt="{imageurl/@imageurldescription}" />
        </a>
    </span>
    <!–Funcion JavaScript para armar la URL hacia el formulario de edición–>
    <script type="text/javascript">
        function GetUrlDispForm(strUrl, idEle)
        {
        var dispForm = strUrl.substring(0,strUrl.lastIndexOf("/"));
        dispForm += "/Forms/DispForm.aspx?ID=";
        dispForm += idEle;
        dispForm += "&amp;Source="+ document.location.href
        window.navigate(dispForm);
        }
    </script>
    <span class="srch-Title">
        <a href="{$url}" id="{concat(‘CSR_’,$id)}" title="{$url}">
            <xsl:choose>
                <xsl:when test="hithighlightedproperties/HHTitle[. != »]">
                    <xsl:call-template name="HitHighlighting">
                        <xsl:with-param name="hh" select="hithighlightedproperties/HHTitle" />
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="title"/>
                </xsl:otherwise>
            </xsl:choose>
        </a>
        <!–XSLT agregado para cada uno de los elementos devueltos por la búsqeda
        Para llevar a cabo esto utilizmos una propiedad llamada isDocument que nos
        indica que el itme que estamos dibujando es un documento.
        –>
        <xsl:if test="isdocument=1">
            <a>
                <xsl:attribute name="href">
                    javascript:GetUrlDispForm(‘<xsl:value-of select="url"/>’,<xsl:value-of select="idelemento"/>);
                </xsl:attribute>
                Editar
            </a>
        </xsl:if>
    </span>
    <xsl:choose>
        <xsl:when test="$IsThisListScope = ‘True’ and contentclass[. = ‘STS_ListItem_PictureLibrary’] and picturethumbnailurl[. != »]">
            <div style=’padding-top: 2px; padding-bottom: 2px;’>
                <a href="{$url}" id="{concat(‘CSR_P’,$id)}" title="{title}">
                    <img src="{picturethumbnailurl}" alt="" />
                </a>
            </div>
        </xsl:when>
    </xsl:choose>
    <div class="srch-Description">
        <xsl:choose>
            <xsl:when test="hithighlightedsummary[. != »]">
                <xsl:call-template name="HitHighlighting">
                    <xsl:with-param name="hh" select="hithighlightedsummary" />
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="description[. != »]">
                <xsl:value-of select="description"/>
            </xsl:when>
        </xsl:choose>
    </div >
    <p class="srch-Metadata">
        <span class="srch-URL">
            <a href="{$url}" id="{concat(‘CSR_U_’,$id)}" title="{$url}" dir="ltr">
                <xsl:choose>
                    <xsl:when test="hithighlightedproperties/HHUrl[. != »]">
                        <xsl:call-template name="HitHighlighting">
                            <xsl:with-param name="hh" select="hithighlightedproperties/HHUrl" />
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="url"/>
                    </xsl:otherwise>
                </xsl:choose>
            </a>
        </span>
        <xsl:call-template name="DisplaySize">
            <xsl:with-param name="size" select="size" />
        </xsl:call-template>
        <xsl:call-template name="DisplayString">
            <xsl:with-param name="str" select="author" />
        </xsl:call-template>
        <xsl:call-template name="DisplayString">
            <xsl:with-param name="str" select="write" />
        </xsl:call-template>
        <xsl:call-template name="DisplayCollapsingStatusLink">
            <xsl:with-param name="status" select="collapsingstatus"/>
            <xsl:with-param name="urlEncoded" select="urlEncoded"/>
            <xsl:with-param name="id" select="concat(‘CSR_CS_’,$id)"/>
        </xsl:call-template>
    </p>
</xsl:template>

 

Lo que nos resta ahora es volver a colocar todo el XSLT nuevamente a la WebPart para de resultado para que la modificación sea tenida en cuenta, para eso copiamos todo él XSLT del Visual Studio y lo volvemos a pegar en él editor, ver imagen 5. Una vez colocado el XSLT guardamos la modificación y salimos del modo de edición para que el cambio sea tenido en cuenta por Sharepoint. Volvemos a realizar la búsqueda y nos encontramos con que todos los resultados del tipo documento cuentan con un link para acceder a las propiedades, ver imagen 6

Imagen 6

image

 

En la siguiente imagen vemos como se despliega el formulario de edición de propiedades del documento al presionar el link “Editar”

Imagen 7

image

 

Lo que vamos hacer ahora es modificar la página avanzada de búsqueda, donde agregaremos una propiedad a los tipos de resultados provistos por la WebPart, que nos permitirá hacer búsquedas avanzadas utilizando esta propiedad. Editamos la página para acceder a las propiedades de la WebPart. Una vez en el modo de edición, del menú izquierdo editamos las propiedades cargadas de la sección de propiedades, una vez en el editor de texto, ver imagen 8, vamos agregar la propiedad “Filename” para que podamos realizar una búsqueda por dicha propiedad. Lo que tenemos que hacer es buscar la sección <PropertyDefs> e inmediatamente debajo de la propiedad “<PropertyDef Name="ModifiedBy" DataType="text" DisplayName="modificado por última vez por"/>” colocamos la definición de nuestra propiedad “<PropertyDef Name="Filename" DataType="text" DisplayName="Nombre del archivo" />”.

Una vez agregada la definición vamos a agregar la misma al tipo de resultado que queremos que aparezca, en nuestro ejemplo vamos a colocarlo dentro del tipo de resultado “<ResultType DisplayName="Todos los resultados" Name="default">”, para ello lo que hacemos es agregar la siguiente línea “<PropertyRef Name="Filename" />” inmediatamente después de la propiedad llamada “ModifiedBy”.

En la siguiente figura vemos como la nueva propiedad que acabamos de agregar al ComboBox de propiedades de la página avanzada de búsqueda es mostrada.

Imagen 8

image

 

En la siguiente imagen vemos él resultado devuelto por él motor de búsqueda utilizando la propiedad “Filename” con el texto “Prerequisites” cargado.

Imagen 9

image

WebControl PeopleEditor Property Webpart Sharepoint 2007

Estábamos desarrollando una WebPart, otro de los requerimientos solicitados por un cliente, cuando con Santiago, Javier y yo nos pusimos a discutir cómo podíamos desarrollarlo. Le empezamos a dar vuelta al tema y encontramos una solución, que se cargara un usuario en las propiedades de las la WebPart que estábamos desarrollando. Entonces decidimos colocar una simple propiedad para que se cargara el usuario que necesitábamos y el usuario final simplemente debía escribir el nombre de un usuario para ser configurado.

Pero Santiago fue más lejos y se puso a investigar cómo se podría utilizar el control de Sharepoint 2007 PeopleEditor para brindar al usuario una forma natural de configurar un usuario en nuestra WebPart.

Las WebParts pueden sobre escribir (override) el método GetToolParts() que devuelve un Array del objeto ToolPart. En este Array vamos a retornar las instancias de dos clases  WebPartToolPartCustomPropertyToolPart del espacio de nombre “Microsoft.SharePoint.WebPartPages” y la instancia de una clase personalizada que nosotros vamos a crear y que extiende de la clase ToolPart que se encuentra en el espacio de nombre ”Microsoft.SharePoint.WebPartPages”.

Lo primero que tenemos que hacer es crear nuestra WebPart, la misma debe heredar de la clase WebPart de Sharepoint, esta clase se encuentra en el espacio se nombre “Microsoft.SharePoint.WebPartPages” puesto que esta clase es la que contiene el método que debemos sobre escribir (override) GetTollParts() y la clase WebPart de Asp.Net no implementa dicho metodo.

En la sección 1 vemos la implementación de nuestra WebPart la cual es una WebPart simple que lo que hace es mostrar los datos del usuario configurado en el control PeopleEditor.

 

Sección 1

 

using System;

using System.Runtime.InteropServices;

using System.Web.UI;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Serialization;

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;

using System.ComponentModel;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

 

namespace Siderys.Blogs.WebPart

{

    [Guid("b604193b-be0f-4b2e-8b82-d9783fe8c262")]

    public class PeopleEditorWebpart : Microsoft.SharePoint.WebPartPages.WebPart

    {

        private SPUser mUsuario = null;

        public PeopleEditorWebpart()

        {

            this.ExportMode = WebPartExportMode.All;

        }

        [Browsable(false)]

        public SPUser Usuario

        {

            get

            {

                return mUsuario;

            }

            set

            {

                mUsuario = value;

            }

        }

        protected override void Render(HtmlTextWriter writer)

        {

            HtmlTable lTable = new HtmlTable();

            HtmlTableRow lRow = new HtmlTableRow();

            HtmlTableCell lCell = new HtmlTableCell();

            if (mUsuario != null)

            {

                //Nombre

                lCell.InnerText = "Nombre: ";

                lRow.Controls.Add(lCell);

                lCell = new HtmlTableCell();

                lCell.InnerText = mUsuario.Name;

                lRow.Controls.Add(lCell);

                lTable.Controls.Add(lRow);

                //Es admin

                lCell = new HtmlTableCell();

                lRow = new HtmlTableRow();

                lCell.InnerText = "Es Admin: ";

                lRow.Controls.Add(lCell);

                lCell = new HtmlTableCell();

                lCell.InnerText = mUsuario.IsSiteAdmin.ToString();

                lRow.Controls.Add(lCell);

                lTable.Controls.Add(lRow);

            }

            else

            {

                lCell.InnerText = "No hay usuario seleccionado";

                lRow.Controls.Add(lCell);

                lTable.Controls.Add(lRow);

            }

           lTable.RenderControl(writer);

        }

        public override ToolPart[] GetToolParts()

        {

            ToolPart[] lToolPart = new ToolPart[3];

            WebPartToolPart lWebPartToolPart = new WebPartToolPart();

            CustomPropertyToolPart lCustomToolPart = new CustomPropertyToolPart();

            lToolPart[0] = lCustomToolPart;

            lToolPart[1] = lWebPartToolPart;

            lToolPart[2] = new ToolPartPeopleEditor();

            return lToolPart;

        }       

    }

}

 

Bien ahora vamos a implementar la clase “ToolPartPeopleEditor” que utilizamos en el método GetToolParts() la cual es la que crea una instancia del control PeopleEditor y la carga en el panel de configuración de la WebPart. En la sección 2 vemos la implementación de la clase mencionada. Esta clase realiza la sobre escritura (override) de los métodos “RenderToolPart”, “CreateChildControls” y “ApplyChanges”. El primer método dibuja el contenido de la clase, el segundo método agrega la instancia del control PeopleEditor creado en el evento “Init” y el último método es utilizado para obtener el valor del control cargado cuando el usuario presiona el botón “Apply”.

 

Sección 2

 

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint.WebControls;

 

namespace Siderys.Blogs.WebPart

{

    public class ToolPartPeopleEditor : Microsoft.SharePoint.WebPartPages.ToolPart

    {

        private PeopleEditor lPeopleEditor = null;

        private const string lNombreControl = "ctl00$MSOTlPn_EditorZone$Edit2g_71a9f59a_11e8_4672_8953_8b96927aee44$PeopleEditorWebPart$downlevelTextBox";

        public ToolPartPeopleEditor()

        {

            Title = "Seleccionar Usuario ToolPart";

            Init += new EventHandler(ToolPartPeopleEditor_Init);

        }

 

        void ToolPartPeopleEditor_Init(object sender, EventArgs e)

        {

            lPeopleEditor = new PeopleEditor();

            lPeopleEditor.ID = "PeopleEditorWebPart";

            lPeopleEditor.AllowEmpty = false;

            lPeopleEditor.ValidatorEnabled = true;

            lPeopleEditor.MultiSelect = false;

            lPeopleEditor.SelectionSet = PeopleEditor.AccountType.User.ToString();

        }

        public override void ApplyChanges()

        {

            PeopleEditorWebpart lPeopleWebPart = (PeopleEditorWebpart)ParentToolPane.SelectedWebPart;

            string lUsuarioCargado = Page.Request.Form[lNombreControl].ToString();

            lPeopleWebPart.Usuario = Microsoft.SharePoint.SPContext.Current.Web.AllUsers[lUsuarioCargado];

        }

        protected override void RenderToolPart(System.Web.UI.HtmlTextWriter output)

        {

            output.Write("<BR/>");

            base.RenderToolPart(output);

        }

        protected override void CreateChildControls()

        {

            base.CreateChildControls();

            Controls.Add(lPeopleEditor);

        }

    }

}

 

Una vez implementado estas dos clases lo que debemos hacer es compilar e instalar la WebPart en nuestro portal de Sharepoint.

En la imagen 1 vemos como configuramos el control en el panel de propiedades de la WebPart y en la imagen 2 vemos como obtenemos el usuario cargado y mostramos algunos de sus valores.

 

Imagen 1

 1_WebPart  

Imagen 2

2_WebPart  

En un próximo artículo vamos a seguir hablando de cómo podemos ir agregando funcionalidades a nuestras WebParts con controles de Sharepoint 2007.

Como usar el control PeopleEditor de Sharepoint 2007

El otro día (vaya a saber uno que día), uno de esos días donde pasamos inmersos frente a la pantalla de nuestra computadora y las agujas del reloj dan vueltas como locas sin parar, me encontré frente a un requerimiento (uno de los tantos que tenia este desarrollo) y que teníamos que resolver. Con Javier veníamos dando dura batalla a todo lo que teníamos que desarrollar, él mano a mano con el WorkFlow y yo mano a mano con los formularios personalizados de las listas. En un momento tuvimos que cambiar el enfoque del desarrollo y salirnos de Infopath 2007 y volcarnos al desarrollo tradicional de WebParts. Otra vez nos encontramos con que Infopath 2007 para Forms Services está limitado y hay cosas que no se pueden hacer (ese es un tema aparte) y desarrollar un formulario utilizando una WebPart para dar de altas elementos en la lista. Una de las cosas que tenía que tener el formulario era la posibilidad de seleccionar usuarios de Sharepoint y cargarlos. Todos hemos trabajados con los formularios que nos proporciona Sharepoint 2007 para las listas. Cuando tenemos un campo del tipo Persona o Grupo, en el formulario se nos  brinda un control que nos permite introducir dicho usuario o grupo, validarlo o desplegar una pantalla para buscarlo, en la siguiente imagen se muestra dicho control.

Imagen 1

persona

Estamos acostumbrados a utilizar este tipo de campos en los formularios de Sharepoint 2007 para cargar personas o grupos. Incluso Infopath 2007 provee un control Activex, Contact Selector para utilizar dicha características en los formularios creados, acá les dejo las dirección a dos artículos de amigos de la comunidad que explican al pie de la letra como utilizar dicho control,

·         Marco

·         Vlad-Point

Nosotros queríamos mantener esta característica en los formularios que estábamos creando, así que decidimos utilizar el control PeopleEditor que nos provee Sharepoint 2007 para incorporarlo en los mismos.
Tomamos la decisión de hacer un control de usuario (ASCX) y después cargarlo en una WebPart utilizando el método LoadControl. Esto fue meramente por simplicidad y velocidad en el desarrollo, puesto que para variar estábamos con los tiempos justos y no quisimos hacer todo el formulario en la WebPart dado que el mismo era bastante complejo y nos llevaría mucho más.
Así que nos pusimos a trabajar, lo primero que tuvimos que hacer fue registrar el Assembly de Sharepoint 2007 que tiene el control (Clase) PeopleEditor utilizando la directiva @Register en nuestro control de usuario, como se puede ver en la sección 1, no se olviden incluir la referencia al Assembly Microsoft.Sharepoint.Dll en su proyecto.

Sección 1

<%@ Register tagprefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Una vez registrado el Assembly correspondiente estábamos en condiciones de poder usar el control en nuestro formulario, así que declarativamente lo incorporamos al mismo como se puede ver en la sección 2.

Sección 2

<SharePoint:PeopleEditor ID="PeopleEditorPersona" AllowEmpty="false" ValidatorEnabled="true" MultiSelect="false" runat="server" SelectionSet="User" CssClass="general_control" />

 

En la sección 3 vemos algunas de las propiedades que podemos establecer en el control PeopleEditor.

 

Sección 3

·         AllowEmpy: propiedad que indica si el control puede estar vacio.

·         ValidatorEnabled: propiedad que indica si la velicación esta activada.

·         MultiSelect: propiedad que indica si podemos selecciona más de un usuario a la vez.

·         SelectionSet: propiedad que indica que tipo de objeto podemos seleccionar, en nuestro caso, solo usuarios.

 

Todos los valores permitidos por la propiedad SelectionSet del control se encuentran listados en la siguiente enumeración dentro de la clase PeopleEditor:

 

Microsoft.SharePoint.WebControls.PeopleEditor.AccountType

 

Para más información de esta enumeración vistitar la pagina del MSDN

 

Una vez el control está cargado en nuestro formulario lo que debemos hacer es colocar el código necesario para poder tomar los usuarios ingresados en el mismo. En nuestra clase asociada al control ASCX nos referimos al control utilizando la propiedad ID  y utilizando la propiedad “Accounts” la cual nos brinda colección de strings con los usuarios cargados en el formato “dominiousuario”.

Con cada elemento de la posición del ArrayList podemos cargar el usuario del sitio Web para tomar sus valores, en la sección 4 vemos el código completo del método asociado al evento click de nuestro botón “Guardar” del formulario y un método adicional que obtiene el usuario de nuestro portal Sharepoint 2007 a partir de la cuenta cargada. Para obtener el usuario del portal utilizamos el objeto SPContext que nos brinda una referencia al contexto de ejecución del sitio actual.

Sección 4

    protected void cmdGuardar_Click(object sender, EventArgs e)

    {

        SPUser lUser = GetUserLogged(PeopleEditorPersona.Accounts[0].ToString());

        lblMsg.Text += "Nombre: " + lUser.Name + "<br>";

        lblMsg.Text += "Login Name: " + lUser.LoginName + "<br>";

        lblMsg.Text += "Email: " + lUser.Email + "<br>";

    }

    private SPUser GetUserLogged(string pUserAccount)

    {

        return SPContext.Current.Web.AllUsers[pUserAccount];

    }

 

En la magen 2 vemos como funciona el control dentro del formulario personalizdo creado para cargar el usuario de Sharepoint.

 

Imagen 2

 formulario