WSS 3.0 & MOSS: Recopilación de enlaces interesantes (XIV)

Para cerrar el mes de enero, aquí os dejamos la entrega nº 14 de recursos y enlaces relevantes sobre plataforma SharePoint. La sección con más novedades es sin duda la relativa a novedades y utilidades que han ido apareciendo recientemente (atención al SharePoint Silverlight Browser).

Artículos & Documentación:

Tips & Tricks

Utilidades, Recursos & Novedades

OBABook2

silverlight1

  • De nuevo en Codeplex, tenemos una nueva release de MOSS Faceted Search. Se trata de un conjunto de web parts para enriquecer las búsquedas en MOSS y Microsoft Search Server.

Como siempre, esperamos que la recopilación ayude a los sufridos desarrolladores en plataforma SharePoint.

MSDN Code Gallery: Snippets, Ejemplos y Recursos en general!

Microsoft acaba de lanzar el MSDN Code Gallery. Se trata de un nuevo portal de recursos diseñado como repositorio único para que cualquiera que habitualmente trabaje con plataforma Microsoft pueda compartir código fuente, snippets y ejemplos de aplicaciones.

image

Como se comenta en este post de SharePoint Buzz, MSDN Code Gallery no es un sustituto o reemplazo para Codeplex, sino que se trata de un medio para facilitar que la comunidad de desarrolladores puedan compartir recursos de manera sencilla. Codeplex en cambio se trata de un repositorio de proyectos reales aplicables a distintas plataformas y tecnologías Microsoft. En lo que a SharePoint se refiere, de momento no hay demasiados recursos (de hecho sólo 4 según la misma fuente):

  • CodeWorld of Microsoft ISV Advisory Community
  • Master Page Commands for MOSS
  • Searching MOSS Resource Files
  • SharePoint List DataTable
  • En mi opinión, se trata de otro portal útil que ya veremos si resulta complementario o no con respecto a otras iniciativas ya lanzadas como es la SharePointPedia para recursos de SharePoint.

    Dynamic LINQ o como construir consultas dinámicas con LINQ!

    Una de las preguntas más típicas que surgen cuando he impartido algún seminario en el que se trata algún tema de LINQ es como se pueden construir consultas dinámicas con LINQ, porque aparentemente LINQ no parece admitir este escenario puesto que la idea es escribir lo que el genial (uno de los grandes “culpables” de el diseño y creación de LINQ)  Scott Guthrie denomina consultas “type-safe”, es decir, consultas en las que tenemos soporte para intellisense, refactoring y comprobación de tipos en tiempo de compilación…pero, que pasa (escenario bastante habitual) si necesito una cierta flexibilidad que implique poder construir consultas más o menos dinámicas (por ejemplo, realizar consultas cambiantes en función de los datos de negocio seleccionados por el usuario de una cierta aplicación)…la clave está en la palabra “aparentemente”, puesto que como viene siendo habitual en los últimos tiempos, LINQ y las innovaciones en el lenguaje proporcionan los elementos adecuados para construir estas consultas dinámicas. En este caso estamos hablando de la LINQ Dynamic Query Library (System.Linq.Dynamic), de la que tenemos ejemplos de uso en la página de ejemplos descargables de VS 2008, o bien:



    Si nos bajamos cualquiera de los archivos de los vínculos anteriores, veremos que se trata de un conjunto de ejemplos sobre LINQ, siendo uno de los mismos el de Dynamic Query. Al abrir la solución, podremos ver que aparte de hacer referencia a la librería comentada (y que es una clase del proyecto de ejemplo que podemos usar), la construcción de una consulta LINQ dinámica tendría la siguiente forma:






    Northwind db = new Northwind(connString);
    db.Log = Console.Out;


    var query =
        db.Customers.Where(“City == @0 and Orders.Count >= @1”, “London”, 10).
        OrderBy(“CompanyName”).
        Select(“New(CompanyName as Name, Phone)”);


    Como vemos, la clave está basada en la definición de expresiones tipo cadena, en lugar de código…¿y cómo es posible esto? Pues a través de una serie de métodos de extensión que permiten construir consultas en base a expresiones en cadena en lugar de las habituales expresiones lambda. Junto con el ejemplo de uso e la Dynamic Query Library viene algo de documentación sobre como utilizarla. Finalmente, comentaros que se puede utilizar para cualquier extensión de LINQ: LiNQ To Objects, LINQ To SQL, LINQ To XML, …

    ADO.NET Entity Framework: LINQ To Entities, Entity SQL y Entity Services (I)

    Para complementar la serie de post que sobre LINQ To Entities y Visual Basic 2008 ha iniciado Jorge Serrano, en este primer post sobre ADO.NET Entity Framework os daré el punto de vista análogo a lo que Jorge ha explicado pero aplicado a la nueva versión de C # que aparece como una de las grandes novedades de Visual Studio 2008: C # 3.0. Antes de entrar en materia, la primera pregunta que se nos puede venir para los profanos en la materia es ¿Qué es ADo.NET Entity Framework? Como se describe en este artículo, una de las metas principales de la nueva versión de ADO.NET es elevar el nivel de abstracción de la programación contra fuentes de datos a través de la eliminación del “vacío” existente entre los modelos de datos y los lenguajes de programación. Y ¿Cómo es posible esto? A través de dos innovaciones claves de las que ya se ha hablado mucho en Geek.Ms: LINQ y ADO.NET Entity Framework. Precisamente éste último (Entity Framework) es un nuevo componente que aparece en familia de tecnologías ADO.NET, que habilitará acceso a datos mediante LINQ utilizando: LINQ To SQL, LINQ To DataSet y/o LINQ To Entities. Si tuviésemos que resumir las características de este Entity Framework, sin duda destacaríamos los siguientes puntos:

    • Se trata de un Framework que permite manipular y acceder a los datos como clases .NET.
    • Permite realizar un modelado de datos a nivel conceptual, es decir, habilita la separación de las aplicaciones y los esquemas de BD.
    • Permite una mejor interactuación de los datos con el entorno .NET: Se interactúa con objetos, frente a hacerlo con filas y columnas.
    • Proporciona una serie de servicios en tiempo de ejecución y en tiempo de diseño que permite a los desarrolladores describir los datos de la aplicación e interactuar con ellos a un nivel de abstracción conceptual claramente alineado con el concepto de implementación de aplicaciones de negocio, y que además ayuda a aislar la aplicación respecto a los esquemas de base de datos (BD) sobre los que se ha definido.
    • Como comentó Jorge en su post, se apoya en LINQ para definir las consultas a objetos del esquema EDM (Entity Data Model).
    • Supone una capa más, pero independiza las aplicaciones de el esquema de BD subyacente, independientemente de la tecnología de BD que se esté utilizando.

    ¿En qué se traduce esta independencia con el esquema de BD y la tecnología de BD? Pues básicamente en una arquitectura dividida en dos partes diferenciadas, Modelo de datos y Modelo Conceptual (EDM), en la que el paso de una parte a otra se realiza a través del correspondiente mapeo. Para realizar este mapeo se utilizan proveedores .NET que permiten interactuar con los datos en cada uno de las partes:

    image

    La idea es que el provider .NET de la capa de datos se encarga de traducir las operaciones de datos realizadas en la capa conceptual a un lenguaje entendible por la BD (lógicamente T-SQL). Por su parte, el proveedor .NET (EntitySQL) de la capa conceptual traduce las consultas LINQ realizadas en las aplicaciones a las correspondientes instrucciones que interactúen con el modelo conceptual definido mediante el proceso de mapeo.

    Una vez repasadas las principales ideas y conceptos que hay bajo ADO.NET Entity Framework, vamos a ver en la práctica en que consiste trabajar en un nivel de abstracción superior. Los requisitos para poder probar ADO.NET Entity Framework ya los comentamos en este post.

    Definiendo el EDM

    Cómo comentó Jorge en su post, el primer paso para trabajar con ADO.NET Entity Framework pasa por crear un modelo de entidades a partir de un cierto esquema de BD. Para ello añadimos al proyecto un elemento de tipo ADO.NET Entity Data Model con lo que se iniciará un asistente que nos guiará en la creación del modelo a partir de:

    • Especificar la opción de generación del EDM (a partir de una BD o bien un EDM vacío.
    • Especificar la cadena de conexión a la BD (que como siempre, puede ser un archivo físico o bien una instancia de SQL Server).
    • Especificar que objetos de la BD queremos que formen de nuestro EDM (en este caso, tablas y procedimientos almacenados).
    Curso_LINQ_Lab4_3 image image

    Tras pulsar Finish en la última pantalla del asistente, ya tendremos creado el modelo de entidades que en esencia es un fichero .edmx que contiene toda la definición del modelo. Si inspeccionamos el modelo veremos:

    • Se han generado tantas entidades como tablas de la BD relacional.
    • Al seleccionar cada entidad, podremos ver los detalles de la misma en cuanto a miembros y la correspondencia de los campos de la entidad con sus equivalentes en la tabla de la BD.
    • El explorador del modelo nos permitirá ir navegando por los componentes del mismo: entidades, asociaciones entre entidades, funciones, etc.
    • Finalmente, para tener una idea del código generado por el asistente, basta con que nos vayamos al Class Viewer o al Object Browser e inspeccionemos los distintos elementos generados.
    image image

    Consultando Entidades

    Como ya comentó Jorge, una de las formas que tenemos para definir consultas contra el EDM es a través de LINQ To Entities que nos dota de toda la potencia y capacidades de LINQ sobre ADO.NET Entity Framework, así como funcionalidad de ORM (Object Relational Model), de manera que los desarrolladores pueden materializar sus entidades en tipos del CLR y programar de forma más sencilla contra el EDM y la base de datos. Lo primero que tenemos que hacer es añadir a nuestra aplicación las sentencias using necesarias:

    • using System.Data.EntityClient;
    • using System.Data.Common;
    • using System.Data;

    El siguiente paso consiste en instanciar el modelo EDM creado y definir la correspondiente consulta LINQ. Por ejemplo:

                //Instancia del modelo de entidades creado

                ClientesModel.Entidades_BD_Clientes ModeloClientes=

                    new ClientesModel.Entidades_BD_Clientes();           

                //Consulta de entidades!

                var clientes =

                    (from c in ModeloClientes.Md_Clientes

                     from v in ModeloClientes.Md_Vehiculos

                     where c.ID_Cliente==v.ID_Cliente

                     select c).Distinct();

                Console.WriteLine(“***********Consulta LINQ To Entities***********”);

                foreach (var c in clientes)

                {

                    Console.WriteLine(“NIF={0}, Direccion={1}”,

                        c.ID_Cliente, c.DireccionCliente + ” ” + c.CiudadCliente);

                }

                Console.ReadLine();

    Como vemos, lo primero que hacemos es crear un objeto denominado ClientesModel que es una instacia de ClientesModel.Entidades_BD_Clientes(). La primera parte se corresponde a nuestro EDM, y la segunda (Entidades_BD_Clientes) es un objeto que ha sido añadida al modelo en el momento de su creación y que hereda de ObjectContext, clase que se encarga de mantener la conexión e información de los metadatos necesaria para leer, escribir, actualizar o borrar entidades en la BD. Además, también referencia la clase ObjectStateManager que se encarga de aspectos relacionados con el tracking de cambios y la resolución de identidades…esto ya lo vimos con LINQ To SQL: si una consulta nos devuelve un objeto del modelo, este es persistido a través de otras consultas mientras que exista el objeto de contexto correspondiente. Sin más, la salida por pantalla que se obtiene de la consulta anterior es:

    image 

    Operaciones de actualización, insercción y borrado de entidades

    Como ocurría con LINQ To SQL, ADO.NET Entity Framework a través de LINQ To Entities nos permite realizar de manera sencilla operaciones de actualización, inserción o borrado a través de la interactuación con las entidades del modelo. Para actualizar una entidad, basta con crear una instancia de la misma a partir de realizar una consulta a la BD de los resultados a actualizar (consulta con C # plano o mediante query expression):

                //Actualización

                Console.WriteLine(“***********Actualizando las Entidades***********”);

                ClientesModel.Md_Clientes ClienteToUpdate =

                    ModeloClientes.Md_Clientes.First(

                        c => c.ID_Cliente == “71505286B”);

                ClienteToUpdate.CiudadCliente=”Torrelavega”;

                ModeloClientes.SaveChanges();           

                foreach (var c in clientes)

                {

                    Console.WriteLine(“NIF={0}, Direccion={1}”,

                        c.ID_Cliente, c.DireccionCliente + ” ” + c.CiudadCliente);

                }

    Como vemos, la clave para llevar los datos a la BD está en el método SaveChanges(). Por otro lado, tal y como sucede con el caso de la primera consulta, gracias a que el objeto ObjectStateManager de encarga del tracking de los datos, los antiguos y nuevos valores se mantienen en el contexto de la aplicación y los cambios se pueden guardar en la BD. La salida por pantalla de la operación de actualización es:

    image

    Para añadir una entidad nueva basta con crear una nueva instancia de la entidad deseada, especificar sus propiedades y añadirla al modelo:

                //Insercción

                Console.ReadLine();

                Console.WriteLine(“***********Añadiendo nuevas Entidades***********”);

                ClientesModel.Md_Clientes ClienteToAdd =

                    new ClientesModel.Md_Clientes();

                ClienteToAdd.ID_Cliente = “72678934C”;

                ClienteToAdd.DireccionCliente = “C/ Ordoño II”;

                ClienteToAdd.CiudadCliente = “León”;

                ModeloClientes.AddToMd_Clientes(ClienteToAdd);

                ModeloClientes.SaveChanges();

                var AllClients =

                 (from c in ModeloClientes.Md_Clientes

                  select c);

                foreach (var c in AllClients)

                {

                    Console.WriteLine(“NIF={0}, Direccion={1}”,

                        c.ID_Cliente, c.DireccionCliente + ” ” + c.CiudadCliente);

                }  

                Console.ReadLine();

    En este caso la clave para preservar los datos en la BD está en el método AddToMd_Clientes() que es generado automáticamente en el modelo de creación del EDM y que recibe un objeto del tipo de la entidada a añadir, así cómo en el método SaveChanges(). La correspondiente salida por pantalla es:

    image 

    Para realizar el borrado de una entidad, se sigue la misma filosofía que para el caso de la actualización e insercción, sólo que en este caso se utiliza el método DeleteObject() y a continuación SaveChanges() para poder llevar los datos a la BD:

    //Borrado

                Console.WriteLine(“***********Borrado de clientes***********”);                

                ClientesModel.Md_Clientes ClienteToDelete =

                    ModeloClientes.Md_Clientes.First(

                        c => c.ID_Cliente == “72678934C”);

                ModeloClientes.DeleteObject(ClienteToDelete);

                ModeloClientes.SaveChanges();

                Console.WriteLine(“Clientes después de borrar”);

                foreach (var c in AllClients)

                {

                    Console.WriteLine(“NIF={0}, Direccion={1}”,

                        c.ID_Cliente, c.DireccionCliente + ” ” + c.CiudadCliente);

                }

                Console.ReadLine();

    La correspondiente salida por pantalla es:

    image

    Y hasta aquí este primer post sobre ADO.NET Entity Framework en la práctica. En el próximo post os introduciré el concepto de Entity SQL y Entity Services, y os mostraré una interesante herramienta que tenemos disponible para facilitar la construcción de consultas contra un EDM. Espero que el post os haya resultado interesante.

    ADO.NET Entity Framework: Lo que necesitas para empezar!

    Si has oído hablar de ADO.NET Framework (por cierto, no esperes que aparezca como parte de .NET Framework 3.5) y estás pensando en probarlo (en ello estoy…), lo primero que necesitas es instalarte en tu entorno los elementos necesarios:

    • ADO.NET Entity Framework, del que actualmente tenemos la versión Beta3 (liberada en diciembre como nos comentó Bruno). El enlace de descarga de la Beta 3 es este.
    • Las Tools para ADO.NET Framework, pero antes de instalárselas y para que no te pase lo que me pasó a mí, tienes que instalarte el siguiente parche para VS 2008.

    image

    En cuanto al enlace de las Tools para ADO.NET Entity Framework, el enlace de descarga es este.

    Y con esto ya puedes empezar a darle caña a ADO.NET Entity Framework.

    LINQ To SQL: Object Identitity y múltiples objetos DataContext

    Una de las grandes características de LINQ To SQL es la capacidad de preservar la identidad y consistencia de objetos al realizar consultas LINQ, incluso en el caso en el que existan varios objetos DataContext. Si dos consultas contienen resultados que se solapan, LINQ To SQL nos devuelve la misma entidad en cada conjunto de resultados de manera que la lógica de la aplicación se simplifica, pues se puede asumir que estos objetos son únicos y de hecho consistentes. Sin embargo, con las API’s tradicionales de acceso a datos, el desarrollador se ve forzado a capturar estos solapes para poder prevenir la creación de múltiples copias idénticas de resultados no únicas. ¿Cómo se gestiona la consistencia de estos objetos? A través del objeto DataContext que asegura la consistencia y unicidad de dichos objetos. Además, en el caso en el que en nuestra aplicación tengamos más de un objeto DataContext, cada uno de esos mantendrá su propia copia individual de objetos.

    Un ejemplo de la preservación de la identidad de objetos en LINQ es el siguiente:

                //Preservación de objetos

                Console.WriteLine("Ejemplo de preservación de objetos");

                CLIENTES_ORMDataContext DB_New_DataContext =

                    new CLIENTES_ORMDataContext();

                var c1 = DB_New_DataContext.Md_Clientes.First();

                var c2 = DB_New_DataContext.Md_Clientes.First();

                Console.WriteLine("Nombre Nº1 = {0}, Nombre Nº2={1}n c1==c2 es {2}",

                    c1.NombreCliente,c2.NombreCliente,

                    object.ReferenceEquals(c1,c2));

                Console.WriteLine("El tipo de c1 es {0}, y el de c2 es {1}",

                    c1.GetType().ToString(), c2.GetType().ToString());

                Console.ReadLine();

    La correspondiente salida por pantalla es:

    image

    Luego efectivamente, los objetos c1 y c2 son idénticos y hacen referencia al mismo objeto con los resultados tal y como atestigua el hecho de que tengan el mismo valor para la propiedad NombreCliente, y sobre todo porque la comparación mediante el método ReferenceEquals devuelve True como era de esperar. Por otro lado, evaluando el tipo de cada uno de los objetos (qué es resuelto dinámicamente por el compilador a partir de la característica de definir tipos implícitamente de C# 3.0) vemos que es el mismo como cabía esperar.

    Como hemos comentado, esta idea de preservación de objetos en cuanto a identidad y consistencia se mantiene aún cuando tengamos múltiples objetos DataContext en nuestra aplicación. En este caso, el código que demuestra esta idea sería el siguiente:

                //Preservación de objetos

                Console.WriteLine("Ejemplo de preservación de objetos");

                CLIENTES_ORMDataContext DB_New_DataContext =

                    new CLIENTES_ORMDataContext();

                var c1 = DB_New_DataContext.Md_Clientes.First();

                var c2 = DB_New_DataContext.Md_Clientes.First();

     

                Console.WriteLine("Nombre Nº1 = {0}, Nombre Nº2={1}n c1==c2 es {2}",

                    c1.NombreCliente,c2.NombreCliente,

                    object.ReferenceEquals(c1,c2));

                Console.WriteLine("El tipo de c1 es {0}, y el de c2 es {1}",

                    c1.GetType().ToString(), c2.GetType().ToString());

                Console.ReadLine();

    La correspondiente salida por pantalla es:

    image

    Luego vemos que efectivamente, los objetos c3 y c4 se refieren a la misma fila de resultado (consistencia), son idénticos en cuanto a tipo, pero al aplicar el método ReferenceEquals vemos que la comparación devuelve False debido a que c3 y c4 ya no se refieren al mismo objeto de resultados, sino que cada uno se refiere a un objeto distinto, ya que en cada caso tenemos un objeto DataContext diferente.

    Finalmente, lo visto aplica si realizamos consultas que para un mismo DataContext devuelvan el mismo resultado: sólo se creará un objeto con los resultados. Así:

                //Preservación de objetos con varios DataContext

                Console.WriteLine("Ejemplo de preservación con una query");

                CLIENTES_ORMDataContext DB_New_DataContext3 =

                    new CLIENTES_ORMDataContext();

                var query1 = DB_New_DataContext3.Md_Clientes.First(

                    q1 => q1.ID_Cliente == "71505286B");

                var query2 =

                    (from q2 in DB_New_DataContext3.Md_Clientes

                     where q2.ID_Cliente == "71505286B"

                     select q2).First();

     

                Console.WriteLine("Nombre Nº1 = {0}, Nombre Nº2={1}n query1==query2 es {2}",

                    query1.NombreCliente, query2.NombreCliente,

                    object.ReferenceEquals(query1, query2));

                Console.WriteLine("El tipo de query1 es {0}, y el de query2 es {1}",

                    query1.GetType().ToString(), query2.GetType().ToString());

                Console.ReadLine();

    La correspondiente salida por pantalla es:

    image

    Como conclusión, esta igualdad entre objetos es realmente importante para un framework de objectos relacionales como es LINQ To SQL puesto que asegura que ante una actualización del estado de una entidad, el cambio se propagará de manera consistente a lo largo de toda la aplicación.

    Espero que el post os haya resultado interesante…seguiremos escribiendo sobre otras características de LINQ que estamos descubriendo y que son espectaculares.

    WSS 3.0 & MOSS: Recopilación de enlaces interesantes (XIII)

    Como se suele decir, no hay mejor forma que empezar el año nuevo con un nuevo recopilatorio de enlaces y recursos interesantes sobre WSS 3.0 & MOSS. Aunque no ha habido demasiado movimiento en la comunidad de SharePoint desde el recopilatorio anterior, aquí os dejamos una serie de nuevos enlaces bastante interesantes…

    Artículos

    Tips & Tricks

    Novedades, Recursos & Otros

    • Una de las preguntas más habituales que nos podemos encontrar sobre la plataforma SharePoint es su integración con el ERP dominante a nivel mundial: SAP. En esta entrada se presentan varios recursos en los que se trata esta cuestión.
    • Todos sabemos que la creación de workflows par SharePoint tiene una cierta complejidad a la hora de modelar escenarios interactivos que impliquen la necesidad de crear formularios para permitir que el usuario pueda participar en el workflow. Pues como no, en Codeplex se ha puesto en marcha un proyecto para facilitar la creación de estos formularios teniendo en cuenta las fases que tiene un workflow en SharePoint…tiene muy buena pinta:

    wss3workflow.jpg

    Weather Web Part Image

     

     

     

     

    • En el mismo blog que la entrada anterior podemos encontrar otra web part muy interesante: CITRIX Web Part.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Y hasta aquí llega la entrega número 13 del recopilatorio de recursos sobre tecnología SharePoint. Esperamos que os resulte interesante y os sirva de ayuda.

    ….y ya son más de 100 millones de Windows Vista

    Aunque ayer fue oficialmente el último día de trabajo de Bill Gates en Microsoft, y como no podía ser de otra forma, se despidió dando una noticia que viene a corroborar la fortaleza de esta gran compañía que formara junto con Paul Allen en el año 1976 (año en el que un servidor ni siquiera era proyecto de persona): la noticia no es otra que Windows Vista superó antes de las navidades del pasado año los 100 millones de unidades vendidas…lo que sin duda es una gran noticia a pesar de que muchos (entre los que me incluyo) hemos vuelto a experimentar algunos sufrimientos actualizados (no se que tienen las últimas actualizaciones de Vista y Office…espero que el SP1 previsto para enero solucione todos estos problemillas).






    billi2.jpg

    Por cierto, ayer en las noticias pude ver vídeo de despedida de Bill Gates que ya nos contó Bruno en su post de ayer…me reí un buen rato, sobre todo cuando salía tocando la guitarra cerca de Bono de U2…como parece que el vídeo en el post de Bruno no tira, os dejo aquí el enlace a la versión que hay en Youtube…


    …sin duda un vídeo para conservar…


    Integración de Reporting Services con SharePoint (III)

    Hace unos meses (abril del año pasado) mi compañero Pablo Sousa escribía dos posts muy buenos sobre la integración de SQL Server Reporting Services (SSRS) y SharePoint (tanto WSS 3.0 como MOSS). En estos posts, Pablo nos explicaba por una parte los pasos configurar SSRS con el SP2 de SQL Server instalado y que permite la integración de SSRS y SharePoint. Además, en este primer post se detallaba las configuraciones necesarias del servidor de SharePoint. En el segundo de los post, Pablo explicaba como crear informes en el entorno de SharePoint gracias a la infraestructura de content types y features que se crean al instalar los Add-In específicos de SSRS para SharePoint. La idea de este post es ir un poco más allá y mostrar como aparecen implementadas en SharePoint funcionalidades típicas del gestor de informes de SSRS: el Report Manager. En particular, os mostraré como crear suscripciones en el entorno de SharePoint, aspectos relativos a la seguridad y otros. Empecemos.

    Tipos de Integración y…un poco de arquitectura

    Antes de meternos en materia, no está de más recordar que hay dos tipos de integración entre SSRS y SharePoint:

    • Visualizar informes en modo no integrado mediante las web parts de SSRS para Sharepoint. El problema de estas web parts (que he podido experimentar) es que son las implementadas para WSS 2.0, y aunque en teoría deberían funcionar perfectamente en WSS 3.0 (por aquello de la famosa compatibilidad entre las web parts de ambas versiones), pues resulta que la conexión entre la Report Explorer Web Part y la Report Viewer Web Part peta de lo lindo.
    • Visualización, diseño y creación de informes en modo integrado a partir de la integración entre SSRS y SharePoint que habilita el SP2 de SQL Server: gestión de informes, interacción, modelo de seguridad de WSS 3.0 aplicado a informes, gestión de suscripciones, etc. Sin embargo, en el modo integrado se pierden algunas de las características típicas de SSRS como por ejemplo el modelo de seguridad basado en roles o la posibilidad de definir informes vinculados a partir de un informe origen.

    Lógicamente, en este post estamos en todo momento trabajando con el segundo tipo de integración caracterizada entre otros por estos puntos:

    • SharePoint es la interfaz unificada de gestión y visualización
    • Informes guardados en librerías: ofrecen versionado, aplicación de workflows, check-in, check-out, etc.
    • Los informes se guardan en la BD de contenidos de SharePoint y se sincronizan automáticamente con BD de Reporting
    • Las funciones de planificación y suscripciones siguen estando en la BD de Reporting
    • Estructura y seguridad propia de SharePoint
    • Report Viewer Web Part: visor de informes, filtrado…esta web part si está implementada de acuerdo al nuevo modelo de ASP.NET 2.0 en el que se basa WSS 3.0 y es mucho más potente que su precedesora.
    image

    Lógicamente para que todo esto sea posible, es necesaria una cierta arquitectura de integración entre SSRS y SharePoint. En la misma, SharePoint hace las veces del Report Manager en un escenario no integrado y el servidor de SSRS hace el papel de Report Server, es decir, se encarga de la ejecución, renderizado, etc de informes.

     

    Básicamente esta arquitectura aporta las características y prestaciones ya comentadas: Almacenar los elementos y propiedades de un informe en las bases de datos de contenido de SharePoint permite buscar en las bibliotecas de SharePoint tipos de contenido del servidor de informes, proteger elementos con los mismos niveles de permiso y proveedor de autenticación que controla el acceso a otros documentos de la empresa alojados en un sitio de SharePoint, usar las características de colaboración y administración de documentos para proteger y desproteger informes para su modificación, usar alertas para descubrir si se ha modificado algún elemento, e incrustar o personalizar el elemento Web Visor de informes en las páginas y sitios de la aplicación. Si dispone de suficientes permisos en un sitio de SharePoint, también puede generar modelos de informe a partir de orígenes de datos compartidos y usar el Generador de informes para crear informes.

    Creación de suscripciones a informes en SharePoint

    La gestión de suscripciones a informes se realiza a dos niveles (de acuerdo a como estructura la información SharePoint):

    • A nivel de biblioteca de informes (Report Library).
    • A nivel de informe.

    Como ocurre con el Report Manager de SSRS, para poder crear suscripciones a informes de manera que estos se entreguen en una cierta ubicación en un cierto instante de tiempo, es necesario que las credenciales de ejecución (usuario y contraseña) del informe estén almacenadas en la BD de Report Server, en la BD master, en la BD msdb y en la BD dónde están los datos en los que se basa el informe. Estas credenciales las podemos crear directamente y de manera visual a través de SQL Server Management Studio o bien con vía script ejecutando el procedimiento almacenado sp_adduser en la BD master y luego asegurarnos que en cada una de las BD’s comentadas estas credenciales tiene permisos de lectura. Si utilizamos sp_adduser:

    use master
    exec sp_addlogin @loginame=’ReportExecution’, @passwd=’pass@word1′

    use rs2005sbsDW
    exec sp_adduser @loginame=’ReportExecution’, @grpname=’db_datareader’

    Una vez que tenemos almacenadas las credenciales en las BD’s comentadas, ya estamos listos para crear nuestra primera suscripción. Para crear una suscripción para un cierto informe, nos vamos a la biblioteca (idealmente una Report Library que hemos configurado con los content types de reporting adecuados) y para un cierto informe veremos que la integración de SSRS con SharePoint nos ofrece entre otras opciones la de Manage Subscriptions, la seleccionamos y seremos redirigidos a una nueva pantalla que nos permite añadir una suscripción a través de Add Subscription, la pulsamos y sorpresa…nos sale un mensaje de error en el que se nos informa (al igual que ocurre en un escenario típico de SSRS con el Report Manager) que: No es posible crear suscripciones puesto que las credenciales no están almacenadas. Proporcione credenciales para el report data source o contacte con el administrador

    image image image

    …aparentemente, el mensaje anterior no tiene sentido puesto que si que hemos creado unas credenciales almacenadas de manera segura en la BD…pero, el mensaje es correcto puesto que no hemos especificado que el data source en el que se basa el informe utilice dichas credenciales para la generación del informe…pues nada, vuelta atrás a la biblioteca de formularios y en este caso pulsamos sobre la opción Manage Data Sources que nos llevará al listado de data sources vinculados al informe. En este caso, sólo tenemos uno, lo pulsamos y seremos redirigidos a la página de detalle del data source en la que podremos especificar que las credenciales de ejecución estén almacenadas en la BD y el valor de las mismas (por defecto, el data source tiene la configuración de ejecución especificada en su creación y que en este caso es Windows Authentication):

    image image image

    En este caso hemos especificado para las credenciales:

    • La opción Stored Credentials y especificamos:
      • User Name: ReportExecution.
      • Contraseña: pass@word1.

    Tras pulsar OK, el informe se ejecutará utilizando las credenciales de acceso a datos que están guardados en la BD. Solucionado el problema de las credenciales, volvemos a la pantalla de Manage Suscriptions. Ahora al pulsar Add Subscription se debería abrir la página de configuración de suscripciones. En dicha pantalla especificamos los parámetros:

    • Delivery Type: Sharepoint Document Library. Podréis comprobar, que se admiten al menos otras dos posibilidades: Null Delivery Provider (para informes que se ejecutan con datos de caché) y File Share Provider (entregarlos en una cierta carpeta compartida). Si además en la configuración de SSRS hemos especificado un servidor SMTP válido, aparecerá la opción de entrega en una cuenta de correo electrónico.
    • Document Library: seleccionamos Shared Documents.
    • Output Format: por ejemplo, TIFF file. Otros posibles formatos de salida son:
    • Delivery Event: pulsamos el botón Configure y especificamos que queremos que el informe se genere de manera diaria y a una hora que sea 5 minutos más tarde que la actual.
    image image image

    Tras pulsar OK, en el listado de suscripciones aparece la suscripción creada:

    image

    Si refrescamos la pantalla después de que haya transcurrido el tiempo programado en la suscripción y veremos que su estado habrá cambiado y nos indicará que el informe se ha creado satisfactoriamente en la ubicación especificada. Finalmente, comprobamos en la librería Shared Documents que se ha generado el informe en formato TIFF…como veis, crear una suscripción en SharePoint implica los mismos paso que en el Report Manager.

    El modelo de seguridad de informes en SharePoint

    Aunque ya lo he comentado, el modelo de seguridad que se aplica a los informes en la integración de SSRS con SharePoint no es el propio de SSRS (basado en roles), sino que se pierde y adopta el modelo propio de SharePoint: seguridad basada en niveles de permisos que a su vez son un conjunto de permisos individuales definidos por defecto en SharePoint (lectura, escritura, etc). A su vez, lo habitual es que definamos grupos de usuarios cada uno de los cuales tendrá un cierto nivel de permisos…por lo tanto, la filosofía a seguir a la hora de securizar la visualización y ejecución de informes es la propia de SharePoint para cualquier otro tipo de documentos o elemento de una lista…en este post ya se comentaron algunas buenas prácticas a seguir a la hora de definir grupos de usuarios en SharePoint.

    Otras cosas que permite la integración de SSRS y SharePoint

    Aparte de las características propias de la integración en cuanto a creación de data models y reports (bien mediante Report Builder o Visual Studio 2005), y lo comentado en cuanto a creación de suscripciones, nos encontraremos con que muchas de las funcionalidades propias del Report Manager están presentes en SharePoint:

    • Manage Parametes, que nos permitirá especificar valores por defecto para los parámetros del informe (si los tiene)o decidir que parámetros ocultar porque no nos interesa que el usuario los utilice para visualizar los resultados.
    • Manage Processing Options, que nos permite especificar el origen de los datos del informe: directamente de la BD (live data), de caché (están almacenados en vistas en la Temp DB de reporting) o bien en base a un snapshot…lógicamente las dos últimas opciones de procesado están pensadas para no penalizar la visualización de informes en escenarios con una alta concurrencia. Además, podremos especificar el timeout permitido y otros parámetros específicos relativos a la ejecución del informe en base a snapshots.
    • View Report History, en el que podremos ver el histórico de ejecución de informes cuando hemos definido que la opción de procesamiento sea snapshot. Desde esta pantalla podremos crear nuevos snapshots o borrar alguno de los existentes.
    image

    image

    image image

    Por supuesto, ante cualquier cambio realizado con estas opciones podremos visualizar el informe y comprobar el resultado.

    image

    Y para finalizar, os voy a comentar otra funcionalidad existente en el Report Manager y que también aparece en la integración de SSRS con SharePoint: Managed Shared Schedules, es decir, la opción de poder definir planificaciones compartidas entre distintos informes. Esta opción está disponible en las Site Settings del sitio de SharePoint y en la sección Reporting Services (creada al activarse la feature de Reporting Services):

    image image image

    Como vemos, y tal y como sucedía al crear una suscripción y especificar el momento de ejecución, para una planificación podremos especificar la frecuencia de la misma, la hora y fecha de inicio, cada cuantas semanas se repite, etc. De hecho, es precisamente al programa una suscripción cuando podemos utilizar estas planificaciones compartidas (opción On a shared schedule).

    Y hasta aquí llega el tercer post de la serie de integración de SSRS con SharePoint. Esperamos que el post os haya resultado de utilidad.