Archivo

Posts Tagged ‘SharePoint 2010’

Consulta, descarga y exportación de perfiles de usuarios en SharePoint


Puedes consultar mi último código en la galería de código de MSDN: consulta, descarga y exportación de perfiles de usuarios en SharePoint. Algunos extractos a continuación.

Introducción

El presente ejemplo muestra cómo utilizar los servicios web para construir una aplicación que permita consultar, descargar y exportar los perfiles de usuario de SharePoint Server 2010, así como información suplemental.

Construyendo el ejemplo

El código de ejemplo es una solución hecha con Visual Studio 2010 para .NET Framework 3.5. No tiene alguna otra dependencia. Hace referencia a dos servicios web, cuyas clases proxy se generaron a partir de los servicios _vti_bin/UserGroup.asmx y _vti_bin/UserProfileService.asmx. El primer servicio está disponible en SharePoint Foundation 2010 y el segundo en SharePoint Server 2010. Nota: este programa funciona también con versiones anteriores de SharePoint, aunque es posible que algunas características no estén disponibles.

Descripción

El programa cuenta con un componente llamado ProfileSource. Éste actúa como fuente de datos para el programa, y contiene los métodos que obtienen la información de los perfiles mediante consultas hechas a los servicios web. Este componente implementa gran parte de la lógica de la aplicación. En particular el método OnDoWork es quien se encarga de descargar la información de los perfiles. A continuación se muestran extractos del mismo.

_worker.ReportProgress(0, Resources.ProfileSource_StartingServices); 
userGroup = new UserGroup(); 
PrepareService(userGroup, _connectionProperties.UserGroupWebService); 
userProfile = new UserProfileService(); 
PrepareService(userProfile, _connectionProperties.UserProfileWebService); 
 
_worker.ReportProgress(0, Resources.ProfileSource_DownloadSchematics);  
Table = CreateTable(userProfile);

El método PrepareService establece algunas propiedades básicas del servicio web, como la URL de donde se encuetra y las credenciales. Nota que éstas últimas varían dependiendo de si el usuario ha seleccionado usar las credenciales por defecto o no. Por otra parte, el método CreateTable utiliza el servicio UserProfileService y su método GetUserProfileSchema para descargar todos los campos disponibles desde el servidor, y con base en ellos generar el esquema de un objeto DataTable.

XmlNode mainNode = null; 
if (ConnectionProperties.AllSiteUsers) 
{ 
    _worker.ReportProgress(0, Resources.ProfileSource_DownloadAllUserInfo); 
    mainNode = userGroup.GetAllUserCollectionFromWeb(); 
} 
else 
{ 
    _worker.ReportProgress(0, Resources.ProfileSource_DownloadUserInfo); 
    mainNode = userGroup.GetUserCollectionFromWeb(); 
} 
_worker.ReportProgress(0, Resources.ProfileSource_UserInfoDownloaded);

El extracto anterior obtiene los usuarios disponibles del sitio (todos los registrados, o bien cualquiera que haya ingresado), mediante la llamada a los métodos GetAllUserCollectionFromWeb o GetUserCollectionFromWeb del servicio web UserGroup, según sea el caso.

XmlDocument doc = new XmlDocument(); 
doc.LoadXml(mainNode.OuterXml); 
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); 
nsmgr.AddNamespace("defns", "http://schemas.microsoft.com/sharepoint/soap/directory/"); 
 
string xpath; 
if (ConnectionProperties.AllSiteUsers) 
    xpath = "defns:GetAllUserCollectionFromWeb/defns:Users/descendant::defns:User"; 
else 
    xpath = "defns:GetUserCollectionFromWeb/defns:Users/descendant::defns:User"; 
XmlNodeList userNodes = doc.SelectNodes(xpath, nsmgr); 

Una vez descargados los usuarios, necesitamos analizar el documento XML regresado. Para ello hacemos uso de XPath. El extracto anterior muestra el código que genera la consutla XPath, y que nos devuelve una lista con todos los nodos que contienen la información de los usuarios.

Posteriormente, recorremos cada elemento de la lista y llamamos al método GetUserProfile, el cual usará al método GetUserProfileByName del servicio web UserProfileService. Los resultados obtenidos los insertamos como una fila en nuestra tabla, como se muestra en el siguiente extracto.

foreach (XmlNode userNode in userNodes) 
{ 
    double stepDouble = ((double)++count / (double)maxCount) * 100.0; 
    int stepInt32 = Math.Min((int)Math.Round(stepDouble, 0), 100); 
    string loginName = userNode.Attributes["LoginName"].Value; 
    _worker.ReportProgress(stepInt32, string.Format(Resources.ProfileSource_DownloadingProfile, loginName, stepInt32)); 
    DataRow row = GetUserProfile(userProfile, loginName); 
    Table.Rows.Add(row); 
 
    if (count >= maxCount) 
        break; 
}

Esta porción de código muestra cómo el método GetUserProfile obtiene el perfil de un usuario.

PropertyData[] allData = service.GetUserProfileByName(loginName); 
foreach (PropertyData data in allData) 
{ 
    if (row.Table.Columns.Contains(data.Name)) 
    { 
        if (data.Values.Length > 0 && data.Values[0].Value != null) 
            row[data.Name] = data.Values[0].Value.ToString(); 
        else 
            row[data.Name] = "[Empty]"; 
    } 
}

Adicional a los métodos mencionados, el componente cuenta con los siguientes miembros.

  • Table. Un objeto DataTable que contiene la información descargada de los perfiles.
  • ConnectionProperties. Un componente ConnectionProperties, el cual contiene la información necesaria para establecer la conexión y descarga de elementos (i.e. usuario, contraseña, URLs, etc.).
  • GetColleagues. Consulta al servicio web UserProfileService por los colegas de un usuario determinado.
  • GetInCommon. Consulta al servicio web UserProfileService por información que el usuario actual tenga en común con otro usuario determinado.
  • GetLinks. Consulta al servicio web UserProfileService por los enlaces de un usuario determinado.
  • GetMemberships. Consulta al servicio web UserProfileService por las membrecías de un usuario determinado.
  • GetOrganizations. Consulta al servicio web UserProfileService por las organizaciones a las que pertenece un usuario determinado.
  • GetPinnedLinks. Consulta al servicio web UserProfileService por los enlaces marcados de un usuario determinado.
  • SaveAs. Exporta los perfiles de usuario hacia un archivo de valores separados por coma (CSV) o a un XML.
  • Loaded. Evento que se dispara cuando el componente ha terminado de descargar la información de perfiles.
  • LoadProgress. Evento que se dispara cuando hay un avance significativo durante la descarga de información de perfiles.
  • ProfileFailure. Evento que se dispara cuando se intenta obtener el perfil de un usuario y éste falla (i.e. por cuestiones de permisos, porque no existe, etc.), en cuyo caso se puede continuar con el siguiente perfil (comportamiento por defecto) o bien terminar con el proceso.
  • Failure. Evento que se dispara cuando la carga de información de usuarios falla y lanza una excepción.

Como última precisión, comentar que el programa está localizado y puede visualizarse en inglés y en español.

Anuncios

Perfiles de usuario e información social


En esta era donde las redes sociales inundan nuestras vidas, es cada vez más común ver empresas y corporaciones que piden características de éstas en sus propios sitios corporativos.

SharePoint 2010 ha dado pasos significativos en esa dirección mediante la provisión de mecanismos para habilitar características similares a las encotnradas en redes sociales. Así pues, cuando un cliente nos pida desarrollar tal o cual característica social, sabremos que podemos apoyarnos en lo que SharePoint nos ofrece.

Quizás lo primero que viene a la mente, al respecto, sean los perfiles de usuario. Es decir, dado un usuario cualquiera en SharePoint, quisiéramos obtener su información particular: nombre, teléfonos, departamentos, móviles, jefe, direcciones, etc. En SharePoint 2010 es posible obtener esta información, si se tienen los permisos necesarios. Existen dos formas de hacerlo: mediante el modelo de objetos de SharePoint, o bien mediante los servicios web que se exponen en /_vti_bin/ de cada sitio. En esta ocasión usaremos los servicios web.

O mejor dicho, usaremos un servicio web en particular: UserProfileService.asmx. Este lo podemos referenciar desde http://misitio/_vti_bin/UserProfileService.asmx. Al hacerlo, nos generará varias clases proxy, entre las que se encuentra UserProfileService.

Vamos por partes. Lo primero que nos interesa es obtener el perfil dado un usuario determinado. Pues bien, es cuestión de llamar a UserProfileService.GetUserProfileByName. Este método toma como parámetro el nombre de la cuenta de un usuario de la forma “dominio\cuenta” (digamos, “ASGARD\thor”) y regresa una colección de objetos PropertyData (esta clase, por cierto, es una clase proxy generada al momento de referenciar el servicio web). Cada PropertyData representa una propiedad del usuario, así que para obtener todas hay que iterar sobre el array.

El siguiente ejemplo muestra cómo obtener la propiedad PreferredName.

using System;
using System.Linq;
using System.Net;
using UserProfileServiceProxy; // el espacio de nombre de tu servicio web
...

UserProfileService service = new UserprofileService();
service.Url = "http://labwf/_vti_bin/UserProfileService.asmx";
service.Credentials = CredentialCache.DefaultCredentials;

PropertyData[] properties = service.GetUserProfileByName("LABWF\\thor");
service.Dispose();

var query = from property in properties
                     where propety.Name.Equals("PreferredName")
                         && property.Values.Length > 0
                         && property.Values[0] != null
                         && property.Values[0].Value != null
                     select property.Values[0].Value.ToString();

string preferredName = query.FirstOrDefault();

                     

Algunas de las propiedades más interesantes (i.e. PropertyData.Name) son las siguientes: AccountName, ADGuid, CellPhone, Department, FirstName, HomePhone, LastName, Manager, PictureURL, PreferredName, SPSBirthday, SPSHireDate, SPSJobTitle, Title, UserName, WebSite, WorkEmail y WorkPhone. Pero hay otras, ¡muchas más!

Si estamos en una aplicación en consola, podemos iterar sobre cada elemento de forma más o menos genérica:

using System;
using System.Linq;
using System.Net;
using UserProfileServiceProxy; // el espacio de nombre de tu servicio web
...

UserProfileService service = new UserprofileService();
service.Url = "http://labwf/_vti_bin/UserProfileService.asmx";
service.Credentials = CredentialCache.DefaultCredentials;

PropertyData[] properties = service.GetUserProfileByName("LABWF\\thor");
service.Dispose();

foreach (PropertyData property in properties)
{
    string name = property.Name;
    string value;
    if (property.Values.Length > 0
        && property.Values[0] != null
        && property.Values[0].Value != null)
        value = property.Values[0].Value.ToString();
    else
        value = string.Empty;

    Console.WriteLine("Propiedad: {0} Valor: {1}", name, value);
}

Ahora bien, aunque es mucha información relacionada al usuario, y ciertamente reviste importancia, no lo es todo en una red social. En particular, nos interesará ver otros elementos que estén asociados a un usuario particular. SharePoint provee, a través del mismo WebService, información adicional. Veamos una por una.

Quizá una de las más usadas es ver qué colegas tiene un usuario determinado. Un colega es un usuario que es marcado como conocido de otro usuario. Así, un usuario determinado puede tener a varios colegas. Esa información se obtiene usando el método UserProfileService.GetUserColleagues, pasando como parámetro la cuenta del usuario en cuestión. Easy peasy:

using System;
using System.Linq;
using System.Net;
using UserProfileServiceProxy; // el espacio de nombre de tu servicio web
...

UserProfileService service = new UserprofileService();
service.Url = "http://labwf/_vti_bin/UserProfileService.asmx";
service.Credentials = CredentialCache.DefaultCredentials;

ContactData[] allData = service.GetUserColleagues("LABWF\\thor");
service.Dispose();

foreach (ContactData data in allData)
{
    Console.WriteLine("Colega: {0}", data.AccountName);
    Console.WriteLine("*** Email: {0}", data.Email);
    Console.WriteLine("*** Group: {0}", data.Group);
    Console.WriteLine("*** ID : {0}", data.ID);
    Console.WriteLine("*** IsInWorkGroup : {0}", data.IsInWorkGroup);
    Console.WriteLine("*** Name : {0}", data.Name);
    Console.WriteLine("*** Privacy : {0}", data.Privacy);
    Console.WriteLine("*** Title : {0}", data.Title);
    Console.WriteLine("*** Url : {0}", data.Url);
    Console.WriteLine("*** UserProfileID : {0}", data.UserProfileID);
    Console.WriteLine();
}

El método GetUserColleagues regresa una colección de ContactData. Ésta clase (igual, proxy generada al referenciar el servicio web) tiene varias propiedades, relacionadas con el colega. Cada elemento de la colección, obvio, representa uno.

Otro aspecto importante que SharePoint ofrece es la posibilidad de que cada usuario tenga un enlace (link), digamos, como favorito. O que otro usuario le envíe un enlace como referencia. Bueno, pues UserProfileService cuenta con dos métodos para llevar a cabo lo anterior: GetUserLink y GetUserPinnerLinks. La diferencia entre ambos es que GetUserPinnerLniks son aquellos enlaces que el usuario ha marcado como favoritos, de manera explícita. El procedimiento es muy similar: ambos métodos regresan una colección de clases proxy, QuickLinkData y PinnedLinkData, respectivamente.

using System;
using System.Linq;
using System.Net;
using UserProfileServiceProxy; // el espacio de nombre de tu servicio web
...

UserProfileService service = new UserprofileService();
service.Url = "http://labwf/_vti_bin/UserProfileService.asmx";
service.Credentials = CredentialCache.DefaultCredentials;

QuickLinkData[] quickLinks = service.GetUserLinks("LABWF\\thor");
foreach (QuickLinkData data in quickLinks)
{
    Console.WriteLine("Enlace: {0}", data.Name);
    Console.WriteLine("*** Group: {0}", data.Group);
    Console.WriteLine("*** ID : {0}", data.ID);
    Console.WriteLine("*** Privacy : {0}", data.Privacy);
    Console.WriteLine("*** Url : {0}", data.Url);
    Console.WriteLine();
}

PinnedLinkData[] pinnedLinks = service.GetUserPinnedLinks("LABWF\\thor");
foreach (PinnedLinkData data in pinnedLinks)
{
    Console.WriteLine("Enlace marcado: {0}", data.Name);
    Console.WriteLine("*** ID : {0}", data.ID);
    Console.WriteLine("*** Url : {0}", data.Url);
    Console.WriteLine();
}

service.Dispose();

Las membresías son otro aspecto interesante que nos ofrece nuestro SharePoint social. Es decir, a qué grupos pertenece tal usuario. Similar a esto, también nos interesa saber a qué organizaciones pertenece el usuario. Para hacerlo, usaremos GetUserMemberships y GetUserOrganization, los cuales regresan (como cabría esperar) una colección de objetos de tipo MembershipData y OrganizationProfileData, respectivamente (¿comienzas a ver el patrón?).

using System;
using System.Linq;
using System.Net;
using UserProfileServiceProxy; // el espacio de nombre de tu servicio web
...

UserProfileService service = new UserprofileService();
service.Url = "http://labwf/_vti_bin/UserProfileService.asmx";
service.Credentials = CredentialCache.DefaultCredentials;

MembershipData[] memberships = service.GetUserMemberships("LABWF\\thor");
foreach (MembershipData data in memberships)
{
    Console.WriteLine("Membrecía: {0}", data.DisplayName);
    Console.WriteLine("*** Group: {0}", data.Group);
    Console.WriteLine("*** ID : {0}", data.ID);
    Console.WriteLine("*** MailNickname: {0}", data.MailNickname);
    Console.WriteLine("*** MemberGroup: {0}", data.MemberGroup.SourceReference);
    Console.WriteLine("*** MemberGroupID: {0}", data.MemberGroupID);
    Console.WriteLine("*** Privacy : {0}", data.Privacy);
    Console.WriteLine("*** Source: {0}", data.Source);
    Console.WriteLine("*** Url : {0}", data.Url);
    Console.WriteLine();
}

OrganizationProfileData[] organizations = service.GetUserOrganizations("LABWF\\thor");
foreach (OrganizationProfileDatadata in organizations)
{
    Console.WriteLine("Organización: {0}", data.DisplayName);
    Console.WriteLine("*** ID : {0}", data.RecordID);
    Console.WriteLine();
}

service.Dispose();

El perfil de un usuario, más su información relacionada (en este caso: colegas, organizaciones, membrecías, enlaces y favoritos) cubre gran parte de la información que uno cabría esperar de una red social (corporativa). Pero SharePoint va un paso más allá: no nada más nos provee la posibilidad de consultar esta información, sino también permite compararla con la de otros usuarios. Por ejemplo: ¿qué usuarios tenemos en común? ¿Qué membrecías compartimos? ¿Cuál es nuestro jefe común?

El servicio web expone el método GetInCommon, el cual toma la cuenta de un usuario como parámetro. Este método compara dicho usuario contra el usuario actual (en este caso, el usuario almacenado en las credenciales del servicio web, o dicho de otra forma, el usuario que manda llamar al servicio web), y rergesa una colección (sorpresa sorpresa) de objetos tipo InCommonData. Esta clase proxy tiene tres miembros: una colección de ContactData, Colleagues, que representa los colegas en común; una colección de MembershipData, Memberships, que representa las membrecías e común; y una propiedad de tipo ContactData, Manager, que representa el jefe en común.

using System;
using System.Linq;
using System.Net;
using UserProfileServiceProxy; // el espacio de nombre de tu servicio web
...

UserProfileService service = new UserprofileService();
service.Url = "http://labwf/_vti_bin/UserProfileService.asmx";
service.Credentials = CredentialCache.DefaultCredentials;

InCommonData data = service.GetInCommon("LABWF\\thor");
service.Dispose();

Console.WriteLine("Jefe común: {0}", data.Manager.Name);

Console.WriteLine("Colegas en común:");
foreach (ContactData colleague in data.Colleagues)
    Console.WriteLine("*** {0}", colleague.Name);

Console.WriteLine("Membrecías en común:");
foreach (MembershipData membership in data.Memberships)
    Console.WriteLine("*** {0}", membership.DisplayName);

Console.WriteLine();

Alternativamente, puedes llamar a los métodos GetCommonManager, GetCommonColleagues y GetCommonMemberships, por separado, si no quieres traerte toda la información.

Pues bien, como puedes ver UserProfileService es el primer paso para crear aplicaciones sociales en SharePoint. Por supuesto, no es la única forma. Ahora hemos usado servicios web, pero también podríamos usar el modelo de objetos. Eso será asunto de otra entrada.

Cinco formas de usar el SPGridView


He publicado recientemente un código en la galería de MSDN. Éste contiene una solución hecha con Visual Studio 2010, la cual tiene cinco ejemplos sobre cómo utilizar el SPGridView de SharePoint.

¡Échale un ojo y descarga el código fuente!

Transcribo porciones del artículo que lo acompaña.

Introducción

La interfaz gráfica de SharePoint contiene diversos controles, los cuales están disponibles para ser usados mediante las librerías de SharePoint como Microsoft.SharePoint.dll.

En diversas ocasiones, al construir WebParts o páginas de aplicaciones, necesitamos mostrar datos de una u otra forma. Una particularmente útil es el empleo de vistas de reja (GridView). Por supuesto, podemos emplear el control GridView nativo de ASP.NET. Afortunadamente, sin embargo, SharePoint cuenta con su propia implementación de este control: SPGridView. Este control cuenta con ciertas configuraciones avanzadas, pero sobre todo, incorpora los estilos nativos de SharePoint, así como un poco de funcionalidad extra.

El código aquí contenido muestra cinco ejemplos sobre cómo utilizar este control:

1.- Cómo utilizarlo dentro de un WebPart.

2.- Cómo utilizarlo de forma declarativa en una página de aplicación.

3.- Cómo añadir un Edit Box Control a una columna del SPGridView.

4.- Cómo añadir paginadores, filtros y ordenamiento.

5.- Cómo usar el control en conjunto con un SPDataSource.

Construyendo el ejemplo

La solución de ejemplo cuenta con una solución para Visual Studio 2010. Al ser para SharePoint 2010, deberá abrirse en una máquina (virtual, por ejemplo) con SharePoint 2010 (Foundation, al menos) instalado. Compilar y desplegar la solución, sin embargo, es tan sencillo como seleccionar las opciones del Visual Studio 2010 y ya.

Ahora bien, dentro del directorio \Fermasmas.Labs.SPGridViewExample\bin\Debug está el archivo Fermasmas.Labs.SPGridViewExample.wsp. Para instalar la solución sin usar el Visual Studio 2010, basta instalar este WSP y luego hacer el deploy. Ejecutar las siguientes líneas de comando con los valores apropiados debe ser suficiente.

stsadm -o addsolution -filename "directorio-al-archivo\archivo.wsp"
stsadm" -o execadmsvcjobs
stsadm" -o deploysolution -name archivo.wsp -url http://tusitio -allowgacdeployment -immediate -force

Posteriormente, sólo será cuestión de activar el feature contenido en el WSP. Al hacerlo, se crearán las listas y páginas necesarias para mostrar los ejemplos, sobre el sitio seleccionado. También aparecerán, en el menú de Acciones del Sitio, cinco entradas, cada una direccionando a la página que contiene el ejemplo.

Descripción

Todos los ejemplos hacen uso de la lista "Asgard List", la cual contiene cierta información pre-cargada.

El primero de ellos muestra cómo crear el SPGridView dentro de un WebPart, llamado GridViewWebPart. El código dentro del método CreateChildControls muestra cómo se crea. Podrás observar que es muy similar a utilizar en GridView. Las diferencias en la interfaz gráfica, sin embargo, son notables. Así es como luce dentro de una página de WebParts:

Notarás que los campos se encuentran agrupados, y que añadimos un campo con una imagen, una flecha, la cual permite seleccionar una fila. La agrupación está habilitada y permite expander y contraer los elementos.

El segundo ejemplo muestra un SPGridView, pero éste se encuentra dentro de una página de aplicación, y como tal, está declarado solamente con marcas de ASP.NET. Para variar un poco respecto al anterior, este control permite editar los elementos al hacer clic en el botón de edición (los cambios se verán reflejados en la lista, por cierto).

El tercer ejemplo muestra el GridView, pero ahora añadimos una columna con un control EBC (Edit Box Control), que es un menú desplegable con diversas acciones. Es un control característico de SharePoint, y todas las listas personalizadas lo muestran en su campo Title. Adicionalmente, la columna de comentarios tiene un cambio. En lugar de mostrar simplemente el texto, ponemos un enlace, el cual al hacer clic abrirá una ventana desplegable (pop-up) donde se muestra el texto del comentario.

Y así es cómo luce el GridView con el EBC, y cómo luce al hacer clic sobre el enlace de comentarios.

En el cuarto ejemplo, la cosa se pone interesante: añadimos paginación, así como la capacidad de filtrar y ordenar, muy à la SharePoint. Y he aquí la imagen.

Ya por último, comentar que hasta el momento todos los ejemplos han hecho uso del ObjectDataSource para hacer el enlazado de los datos (quizás quieras revisar la clase AsgardSource, pero ahí no hay más que abrir la lista y obtener el DataTable de los elementos). En este último ejemplo mostramos cómo usar el SPGridView en conjunto con SPDataSource, un control que nos permite enlazar de manera fácil contra listas y otros elementos de SharePoint. No hay imagen, porque la vista es similar a las anteriores, pero sí hay fragmento de código a continuación.

Código fuente

    Hay bastantitos archivos, como cabría esperar en una solución para SharePoint. Veamos algunos de los importantes.

    • AsgardContentType\Elements.xml – define el tipo de contenido para la lista que usamos como fuente de datos.
    • AsgardList\Elements.xml – define la lista que usamos como fuente de datos.
    • AsgardList\Schema.xml – define la vista de la lista y su asociación con el content-type del primer punto.
    • AsgardList\ListInstance1\Elements.xml – define una instancia de la lista definida en el punto anterior y añade información pre-cargada.
    • AsgardPagesLibrary\Elements.xml – define una biblioteca de documentos donde podemos guardar páginas web. Aquí estará contenida la página de WebParts donde se muestra el ejemplo 1.
    • GridViewWebPart\Elements.xml – define un WebPart a utilizar en el ejemplo 1.
    • GridViewWebPart\GridViewWebPart.webpart – declara las propiedades iniciales del WebPart del punto anterior.
    • GridViewWebPart\GridViewWebPart.cs – el código C# del WebPart.
    • Layouts\Fermasmas.Labs.SPGridViewExample\GridPageFilterSortExample.aspx y GridPageFilterSortExample.cs  – página ASPX con su archivo de código para el ejemplo 4.
    • Layouts\Fermasmas.Labs.SPGridViewExample\GridPageSimpleExample.aspx y GridPageSimpleExample.cs  – página ASPX con su archivo de código para el ejemplo 2.
    • Layouts\Fermasmas.Labs.SPGridViewExample\GridPageWithDataSource.aspx y GridPageWithDataSource.cs  – página ASPX con su archivo de código para el ejemplo 5.
    • Layouts\Fermasmas.Labs.SPGridViewExample\GridPageWithEbcExample.aspx y GridPageWithEbcExample.cs  – página ASPX con su archivo de código para el ejemplo 3.
    • Layouts\Fermasmas.Labs.SPGridViewExample\ViewComments.aspx y ViewComments.cs – página que muestra un comentario pasado por parámetro de página.
    • Model\AsgardSource.cs – archivo C# que contiene una clase usada en los ObjectDataSource de diversos ejemplos.
    • Pages\AsgardWebPartPage.aspx – define una página de WebParts y carga de forma predeterminada el WebPart del ejemplo 1.
    • Pages\Elements.xml – define un módulo, el cual contiene la página de WebParts del punto anterior.
    • SiteActionMenu\Elements.xml – define los elementos añadidos al botón Acciones del Sitio, lo cual mejora la navegación.

    Algunos recursos sobre FAST Search Server


    Si usas SharePoint sabes que 2010 viene con FAST Search Server for SharePoint. Ésta es una herramienta poderosísima de búsqueda, tanto para sitios internos como externos y bases de datos.

    Para programar contra FAST, haré una serie de artículos. Pero por el momento, revisa estos recursos.

    1.- Consulta FAST Search Server desde aplicación cliente. Me sirvió mucho este tutorial, y en esencia lo que dice es que uses el servicio web Search.asmx provisto por SharePoint.

    2.- FAST Query Language. FAST usa un lenguaje llamado FQL para realizar consultas personalizadas. Explora su contenido.

    3.- Ejemplo Sencillo sobre FQL. Pues eso, un ejemplo sencillo.

    Espero sirvan de introducción. Kudos al equipo de MSDN por esta documentación. También, si saben de más ejemplos, no duden en dejar el comentario, ya que es información difícil de localizar.

    Tschüss!

    Obtener la dirección del perfil de un usuario en SharePoint 2010


    Un pequeño tip / código para obtener el perfil de un usuario en SharePoint 2010. Tienes que referenciar la librería Microsoft.Office.Server.UserProfiles para que funcione.

    SPServiceContext context = SPServiceContext.GetContext(Web.Site);
    UserProfileManager manager = new UserProfileManager(context);
    
    string userLogin = "dominio\\usuario";
    UserProfile profile;
    if (!manager.UserExists(userLogin))
        profile = manager.CreateUserProfile(userLogin);
    else
        profile = manager.GetUserProfile(userLogin);
    url = profile.PersonalUrl.ToString();
    

    En la línea 1 obtenemos un contexto de servicio, mientras que en la 2 obtenemos el administrador del perfil. En la sexta línea revisamos si existe el perfil del usuario, y si no existe la creamos. Si sí existe, obtenemos el perfil.

    Por último, la propiedad PersonalUrl de UserProfile contiene un Uri hacia el perfil del usuario. Schön gut!

    Problemas al mostrar ventana emergente


    Hace unos días escribí sobre cómo mostrar una ventana emergente en SharePoint. Pues bien, todo se reducía a un simple código con JavaScript, el cual reproduzco:

    <script type="text/javascript" language="javascript">
        function openAsgardDialog()
        {
            var options = {
                url: "/Pages/AsgardPantheon.aspx",
                width: 800,
                height: 650,
                title: "Hola mundo",
    	    };
    	    SP.UI.ModalDialog.showModalDialog(options);
        }
    </script>";
    

    Ahora bien, ese código funciona bien… o eso pensé. Resulta que correr eso en el Internet Explorer 7 nos piña y nos manda un error, diciendo que no se pudieron cargar los controles Ajax. El hecho, sin embargo, es que esta sintaxis no le funciona, al parecer. Estuve investigando y aquí hay una sintaxis alternativa para iniciar el objeto. Por lo demás, queda igual…

    <script type="text/javascript" language="javascript">
        function openAsgardDialog() 
        {
            var options = SP.UI.$create_DialogOptions();
            options.url = "/Pages/AsgardPantheon.aspx";
            options.height = 800;
            options.width = 650;
            options.title = "Hola mundo";
    
    	    SP.UI.ModalDialog.showModalDialog(options);
        }
    </script>
    

    Una sintaxis un poquito más tradicional, pero funciona con IE 7.

    Mostrar una ventana emergente desde un WebPart


    En SharePoint 2010 introdujeron para muchas cosas ventanas emergentes, aprovechando que todo el sitio ahora cuenta con soporte para Ajax a través del UpdatePanel. Para que podamos hacer algo similar, basta usar un sencillo código en JavaScript.

    <script type="text/javascript" language="javascript">
        function openAsgardDialog() 
        {
            var options = {
                url: "/Pages/AsgardPantheon.aspx",
                width: 800,
                height: 650,
                title: "Hola mundo",
    	    };
    	    SP.UI.ModalDialog.showModalDialog(options);
        }
    </script>";
    

    Al ser invocada dicha función, aparecerá una ventana emergente con el título y dimensiones especificadas, y cargará la página /Pages/AsgardPantheon.aspx, o cualquier otra que especifiquemos.

    Ahora bien, para hacer esto desde un WebPart, tres cosas deben ocurrir.

    1.- Asegurarnos que el master page cuenta con un UpdatePanel. Esto es esencial, puesto que si no Ajax no funciona. Es el comportamiento por default en SharePoint, sólo una precaución por si alguien lo quitó.

    2.- El WebPart deberá registrar el script que permitirá mostrar la ventana emergente.

    private void RegisterOpenHelloWorldDialogScript()
    {
        string script =
            @"<script type=""text/javascript"" language=""javascript"">
                function openAsgardDialog() 
                {{
                    var options = {{
                        url: ""{0}/Pages/AsgardPantheon.aspx"",
                        width: 800,
                        height: 650,
                        title: ""ASGARD"",
    	            }};
    	            SP.UI.ModalDialog.showModalDialog(options);
                }}
                </script>";
        script = string.Format(script, SPContext.Current.Web.Url);
    
        Page.ClientScript.RegisterClientScriptBlock(GetType(),
                "OpenAsgardDialogScript", script);
    }
    
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
    
        RegisterOpenHelloWorldDialogScript();
    }
    

    3.- Llamamos a nuestro JavaScript desde algún control. En este caso, creamos una etiqueta <a> que haga lo propio.

    protected override void CreateChildControls()
    {
        Literal literal = new Literal();
        literal.Text = "<h3>Ejemplo Ventana Emergente</h3>" +
                               "Haga <a href="\&quot;#\&quot;" onclick="\"javascript:openAsgardDialog();\"">" +
                               "click aqu&iacute;</a> para abrir. ";
        Controls.Add(literal);
    }
    

    Y eso es todo. Una imagen de cómo luciría el WebPart…

    image

    …y la ventana emergente.

    image