Friday, August 05, 2011

SharePoint y OBAs Part II

De regreso y avanzando con esta serie de entradas relacionadas a soluciones de SharePoint que involucran una WebPart e interacción con un cliente Office como Excel, voy a seguir dejándoles algunos ejemplos de código que he usado para esto.

Ver Parte I

Qué se debe hacer cuando necesitamos obtener las vistas que pertenecen a una lista específica?

public IList < TGLista > GetViews(Guid idList)
{
SPWeb webList = this.GetWebByIdList(idList);
if (webList != null)
{
TGLista vista = null;
IList vistas = new List();
SPList listaTemp = null;
try
{
listaTemp = webList.Lists[idList];
foreach (SPView temp in listaTemp.Views)
{
vista = new TGLista();
vista.Id = temp.ID;
vista.Titulo = temp.Title;
vistas.Add(vista);
}
}
catch (SPException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
if (webList != null)
webList.Dispose();
}

if (vistas != null)
{
//Hace un ordenamiento ASCENDENTE de la lista
var list = from temp in vistas
orderby temp.Titulo
select temp;
return list.ToList();
}
}
return null;
}

Nuevamente se aprecia el uso de una clase entidad para almacenar la información a pasar entre capas usando una colección genérica de dichos objetos.

Quizá lo que más rescato como buena práctica del método anterior es que si se fijan, el método recibe por parámetro el ID de la lista para la cual queremos obtener sus vistas. No el nombre de la lista (string) o su índice dentro de alguna colección, que puede ser un entero. No se recibe su GUID que es la técnica mejor considerada cuando uno quiere referirse a una lista de SharePoint. La razón que más me gusta y que resguarda las soluciones de problemas "tontos", es que aunque los usuarios finales cambien el nombre de la lista (título o caption), el ID interno se conserva, y eso ya evita que el código quede "débil". Si el usuario borra su lista, apague y vámonos, ahí no hay anda que hacer, pero bueno eso ya son situaciones que se corrigen con un buen entrenamiento y conocimiento de los usuarios de las soluciones.


Un poco de CAML, como buena práctica no le cae mal a una solución SharePoint 2007.

private SPListItem GetItemByTitle(string titulo)
{
SPWeb web = SPContext.Current.Site.RootWeb;
SPQuery query = new SPQuery();
query.Query = "" + titulo + "";
try
{
SPList list = web.Lists["Objetivos KPI"];
foreach (SPListItem item in list.GetItems(query))
{
return item;
}
}
catch (Exception ex)
{
throw;
}
return null;
}

Lo único más interesante a rescatar es el uso de la consulta CAML que lo único que hace es filtrar los ítems de la lista por un título dado. De aquí solamente quiero decirles que usen herramientas como CAML Builder

Y qué pasa cuando quiero guardar un archivo generado por la solución en una biblioteca de SharePoint?

public void SaveLibrary(string file,Stream stream,Guid idList)
{
SPFolder spFolder = null;
SPFile spFileTemp = null;
TGServices services = new TGServices();
SPListItem item = null;
try
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPWeb web = this.GetWebByIdList(idList))
{
web.AllowUnsafeUpdates = true;
spFolder = web.Folders["Plantillas Excel"];
spFileTemp = spFolder.Files.Add(file, stream, true);
spFolder.Update();
item = spFileTemp.Item;
item.UpdateOverwriteVersion();
web.AllowUnsafeUpdates = false;
}
});
}
catch (SPException ex)
{
throw;
}
catch (Exception ex)
{
throw;
}
finally
{
if (stream != null)
stream.Close();
}
}

Y para usar el método anterior podría tenerse algo similar:

FileInfo fileToLibrary = null;
try
{
fileToLibrary = new FileInfo(file);
link = services.SaveLibrary(file, fileToLibrary.OpenRead(), new Guid(IdLista));
}


Lo primero que el método recibe es el nombre de un archivo por ejemplo miarchivo.xlsx. Luego lo más importante recibe un Stream, en el ejemplo anterior se muestra cómo crear dicho stream y pasárselo al método en modo openRead(). Y finalmente pasar el ID de la lista, que quizá nos sirva como fuente para obtener el sitio de ejecución del proceso.

Muy importante la línea SPSecurity.RunWithElevatedPrivileges(delegate()
porque ejecuta el proceso de guardar a la biblioteca de documentos Plantillas Excel en un modo de privilegios elevados, así no tener problemas de acceso negado si el usuario ejecutando la solución no tiene suficientes permisos sobre la biblioteca.

Y siendo el resto de código algo entendible, lo realmente importante es dejar la seguridad de la ejecución como estaba web.AllowUnsafeUpdates = false;
Eso indica que solo ese tramo del código fue elevado, el resto de la ejecución continuará con los permisos del usuario que está ejecutando la solución.


Feliz coding!!

Thursday, August 04, 2011

Arquitectura SharePoint

Creo que para todos los que nos movemos en proyectos que involucran a la plataforma SharePoint, teniendo en mente proyectos de un tamaño mediano a grande. Es un hecho la necesidad de tener una arquitectura y una planificación en general de lo que va a ser la solución en términos de los requerimientos del negocio. Con SharePoint 2010, los elementos de arquitectura a considerar siguen siendo los mismos básicos de la plataforma empresarial 2007. Pero cuando uno revisa en detalle la nueva versión, comienza a encontrar elementos que han sido totalmente rediseñados, y es muy importante tener elementos de donde poder arrancar para poder establecer nuestras arquitecturas iniciales.

En el repositorio de Microsoft hay un gran número de documentos, artículos, gráficos, en fin, mucha información, que personalmente pienso debería haber sido organizada de otro modo, y ser un poco más descriptiva y práctica. Pero siendo eso lo que tenemos de primera mano para planear las primeras etapas de la arquitectura, no está demás arrancar por ahí. Lo que uno si nota es que al menos eso da una idea de los elementos primarios que uno debe considerar en una arquitectura de una solución SharePoint, por ejemplo: Planeación de sitios, Planeación de Seguridad, Planeación de Aplicaciones de Servicio (nuevo en SP 2010), y en general planeación de los elementos que van a impactar sobre las necesidades del negocio: gestión documental, gestión de contenido web, inteligencia de negocio, interacción social, entre otros.

Planning and Architecture

Específicamente cuando se va a realizar una planeación y arquitectura para un tema como Gestión Documental, en SP 2010 aparecen elementos muy importantes, que deberán tenerse muy en cuenta para implementar una verdadera solución de gestión documental con SharePoint. Aparecen aplicaciones de servicio como es la de Metadata Administrada. Esto habilita posibilidades que no existían en SP 2007, como por ejemplo poder tener verdaderas taxonomías de información. Almacenes de términos, sinónimos, centros de registros, tag sociales, conjuntos de documentos, IDs de documentos, HUBs de tipos de contenido, y muchos otros elementos, van atados a este nuevo servicio empresarial. Si realmente se requiere una solución de gestión documental lo suficientemente avanzada, un arquitecto mínimamente deberá entender todos los conceptos subyacentes y por supuesto tener idea cómo se implementan y usan en SP 2010.

Metadata Administrada

Otro elemento esencial en la planeación y arquitectura de una solución SharePoint es un Plan de Gobierno. Esto para muchas empresas llega a ser un tema nuevo, pero si la empresa es grande, tiene la plataforma SP y no tiene políticas y estándares para la misma implementados, antes de hacer nada debería iniciar a crear un Plan de Gobierno. Esto termina siendo un documento donde se consignan las "leyes" que absolutamente todo el mundo en la organización deberá respetar y cumplir.

Plan de Gobierno

Quiero hacer claridad en que no se debe desmeritar todo esto en soluciones más pequeñas, pero bueno, un arquitecto debe poner en la balanza, soluciones, presupuestos, tiempos, y en general los recursos de cada proyecto, para ver si ameritan contemplar todos estos elementos. Es lo ideal tener en cuenta todo esto, pero requiere tiempo y eso significa dinero.

Todo lo anterior es la globalidad de las cosas o elementos que las necesidades de negocio van a requerir de una solución SharePoint. Pero llegan a terrenos más personales, qué hay de la arquitectura de desarrollos .NET para SharePoint?

Lo primero que una Arquitecto SharePoint que tenga dentro de sus soluciones implementar elementos con la plataforma .NET para SharePoint debe conocer es lo que Microsoft ya ha preparado como una vista rápida de los elementos arquitectónicos que se deberán tener en cuenta para los desarrollos o personalizaciones sobre SharePoint 2010 específicamente, igual lo hay para las versiones anteriores.

Software development kit

SharePoint Guidance

Algo insólito, y pienso que no se hace en muchos casos es el uso de UML en proyectos .NET para SharePoint, al menos ningún libro, artículo, en general ningún "gurú" habla del tema. Más allá de los "monachos" UML, lo preocupante es la falta de propaganda de los patrones de diseño que una buena solución .NET para SharePoint mínimamente deberá implementar. Hablo de UML porque es nuestro lenguaje formal para dar a entender los patrones. De los cientos de libros de desarrollo que hay para SP 2010 y 2007, es ya aburridor y tentador para la hoguera, su insufrible repetición de lo mismo con distintas palabras de lo que todos ya sabemos: WebParts, receptores de eventos, listas, bibliotecas, en fin temas de desarrollo que realmente deberían subirse de categoría y mostrar soluciones más serias de ejemplo en estos relucientes libros de 500 a 1000 páginas.

Feliz Arquitectura

Wednesday, August 03, 2011

SharePoint 2007 y OBAs

Hola de nuevo. En dias pasados había estado desarrollando una solución en SharePoint Server 2007, exactamente una WebPart, que tenía como finalidad tomar datos de SharePoint (KPIs) y los exportaba a un template de Excel donde esos datos terminaban siendo tabulados, aplicados sobre formulas, y en otras páginas del archivo Excel gráficados. Quisiera compartir algunas rutinas de código comunes que se usaron, que quiza puedan ser de utilidad a la comunidad.

Anoto que los ejemplos son fragmentos de toda la solución, así que recibirán parámetros, tendrán nombres específicos, llamados quizá a otros métodos, que ya ustedes deberán modificar según su necesidad.

1. Lo primero que vale la pena aclarar es que para esta solución SharePoint se hace uso de WSPBuilder, se los recomiendo, y aquí pueden ver su uso.

2. Debido a que se utilizó OPEN XML SDK para todo lo que tenía que ver con las operaciones sobre Excel del lado del servidor, para finalmente producir un archivo en formato XLSX, les recomiendo mucho usar el SDK provisto por Microsoft, pero ante todo denle una mirada a esta herramienta (Open XML SDK Tool).

Es una herramienta bastante buena que les acepta un archivo Excel en formato XLSX, y finalmente les genera el código C# que permitiría producirlo. Es una ventaja porque uno puede hacer un archivo de prueba, tal como quiere generarlo, y ahorrarse mucho tiempo de desarrollo desde ceros. Toca ajustarlo a lo dinámico de la solución, pero eso ya es algo que evidentemente debe hacerse, pero la estructura general del desarrollo, estaría lista.

3. Ya en código, tú primer requerimiento puede ser obtener todas las listas genéricas (evitar las listas especiales de SharePoint) del site collection y de todos sus sitios hijos, para que con ese listado llenar un control en la capa de presentación que podría ser un ComboBox, un ListBox, etc

public IList < TGlista > GetListas()
{
SPWeb web = SPContext.Current.Site.RootWeb;
TGLista lista = null;
SPListCollection listasTemp = web.Lists;
IList listas = new List();
try
{
if (listasTemp != null)
{
foreach (SPList listaTemp in listasTemp)
{
if (listaTemp.BaseTemplate == SPListTemplateType.GenericList)
{
lista = new TGLista();
lista.Id = listaTemp.ID;
lista.Titulo = listaTemp.Title;
listas.Add(lista);
}
}
}

SPWebCollection webs = web.Webs;
if (webs != null)
{
foreach (SPWeb webTemp in webs)
{
try
{
listasTemp = webTemp.Lists;
foreach (SPList listaTemp in listasTemp)
{
if (listaTemp.BaseTemplate == SPListTemplateType.GenericList)
{
lista = new TGLista();
lista.Id = listaTemp.ID;
lista.Titulo = listaTemp.Title;
listas.Add(lista);
}
}
}
finally
{
if (webTemp != null)
webTemp.Dispose();
}
}
}

if (listas != null)
{
//Hace un ordenamiento ASCENDENTE de la lista
var list = from temp in listas
orderby temp.Titulo
select temp;
return list.ToList();
}
}
catch (Exception ex)
{
throw;
}
return null;
}
Lo primero que se observa es lo que retorna el método:IList < TGlista > . TGLista no es más que una clase entidad, que sirve como contenedor para generar un listado genérico de tipos TGLista, lo cual es ya una técnica de programación muy sencilla y fácil de pasar datos entre las diferentes capas de la solución .NET. El control de la capa de presentación aceptará el tipo IList sin ningún problema.

Luego en la linea SPWeb web = SPContext.Current.Site.RootWeb; se obtiene un objeto de tipo SPWeb, pero usando la clase SPContext, lo cual es la técnica recomendada cuando se programa una WebPart que estará dentro del contexto del sitio de SharePoint. Super importante, no se hace DISPOSE de la instancia web.

Esta linea if (listaTemp.BaseTemplate == SPListTemplateType.GenericList) es la que evita que en el listado se obtengan las listas especiales de SharePoint.

Ahora bien, el requerimiento incluia las listas de los sitios hijo del SiteCollection. Esta linea obtiene todos los sitios hijo SPWebCollection webs = web.Webs; Ahora con esa colección por cada sitio hijo se obtienen su listas del mismo modo. Importante el DISPOSE que si se debe hacer de cada subsite.

finally
{
if (webTemp != null)
webTemp.Dispose();
}

La razón de lo anterior es que cada subsite obtenido es un nuevo SPWeb que en este caso si debe hacerse DISPOSE formal.

Finalmente un poco de LINQ no hace daño para ordenar la lista generica de elementos.
if (listas != null)
{
//Hace un ordenamiento ASCENDENTE de la lista
var list = from temp in listas
orderby temp.Titulo
select temp;
return list.ToList();
}

Por ahora esto es todo, luego seguiremos compartiendo más TIPs de código .NET para SharePoint.

Felíz Coding!!