Configurar la autentificación de SharePoint para utilizar varios directorios activos

Hace tiempo publicamos un post en el que se explicaban los pasos que hay que realizar para poder configurar en un mismo sitio SharePoint diferentes formas de autentificación, utilizando autentificación Windows para la zona intranet, con cuentas locales o de directorio activo y para la zona internet la autentificación basada en formularios, con cuentas de usuarios que estaban almacenadas en una base de datos utilizando los membership provider que nos proporciona ASP. Net 2.0.

Ahora vamos a explicar cómo podemos realizar este mismo proceso de acceder a un sitio de SharePoint utilizando diferentes formas de autentificación, pero en vez de utilizar cuentas de usuarios almacenadas en una base de datos, vamos a crearnos un membership provider para poder utilizar cuentas de usuarios de un segundo directorio activo diferente al que se está utilizando el propio servidor de SharePoint.

Para realizar esta configuración de habilitar la autentificación de usuarios contra varios AD hay que realizar los siguientes pasos:

1. Extender la aplicación web que queremos que tenga esta autentificación contra un segundo AD

2. Realizar los siguientes cambios en el web.config tanto de la administración central como de la propia aplicación web que hemos extendido. Este fichero normalmente se encuentra en c:InetpubwwwrootwssVirtualDirectories[puerto], pero para conocerlo realmente se puede consultar las propiedades del sitio de SharePoint en el IIS y consultar la ficha de Home Directory.

image

3. Insertamos las siguientes líneas de código en los ficheros:

  • Después de la sección configSections ponemos la cadena de conexión con el segundo AD.
<connectionStrings>
 <add connectionString=”LDAP://server/CN=Users,DC=ciin,DC=local” name=”ADConnString”/>
</connectionStrings>
  • Y dentro de la sección system.web establecemos el proveedor de autentificación que luego utilizaremos en SharePoint.

<membership defaultProvider=”ADProvider”>
   <providers>
      <add name=”ADProvider”
         type=”System.Web.Security.ActiveDirectoryMembershipProvider,
         System.Web, Version=2.0.0.0, Culture=neutral,
         PublicKeyToken=b03f5f7f11d50a3a”
         connectionStringName=”ADConnString”
         connectionUsername=”ciin.localAdministrator”
         connectionPassword=”password”
         attributeMapUsername=”SAMAccountName”/>

</providers>
</membership>

Nota: Observar que la contraseña que se establece en el web.config del usuario con los permisos necesarios para acceder al segundo AD y validar al usuario va a estar en texto plano. En los siguientes links se explica como se puede encriptar esta información:

How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI

How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA

4. Cuando hayamos realizado estas modificaciones en los ficheros web.config tanto de la adminstración central como del sitio extendido, solo nos que da modificar el proveedor de autentificación de esta aplicación web desde la administración central y añadir a un usuario perteneciente a este segundo AD como administrador del sitio. Para ello vamos a realizar los siguientes pasos:

  • Entrar en la Administración central de SharePoint y pulsar sobre la opción de ‘Proveedores de autentificación’ dentro del menú ‘Seguridad de aplicaciones’

image

  • Seleccionamos la zona de la aplicación web que hemos extendido y en la que queremos que tenga la autentificacion basada en formularios contra el segundo AD

image

  • Modificamos los parámetros del tipo de autentificación estableciendolo el uso de formularios y luego ponemos el proveedor creado en el web.config ‘ADProvider’

image

  • Por último nos queda añadir un usuario administrador perteneciente al segundo AD en la colección del sitio perteneciente a la aplicacion web extendida desde la opción de ‘Administradores de la colección de sitios’ del menú ‘Administración de sitios de SharePoint’.

image

Diferencias en la integración de Microsoft Office 2003 y 2007 con SharePoint

Una de las principales características de SharePoint es su integración con toda la gama de productos de Microsoft Office, y siempre, al hablar de esta integración en los diversos cursos que se imparten en el CIIN, es una de las preguntas típicas que nos hacen, de cómo es esta integración, que hace, como funciona, y lo más importante, ¿que diferencia hay en utilizar los productos de Microsoft Office 2003 y los de Microsoft Office 2007?.

Siempre decimos que la nueva versión de SharePoint se integra perfectamente con la nueva plataforma de Microsoft Office 2007, pero para saber que pros y contras hay en utilizar esta versión o las anteriores, aquí os dejamos un link al documento titulado “Microsoft Office Programs and SharePoint Products and Technologies Integration – Fair, Good, Better, Best” que publicarón en un post del blog del grupo de producto de SharePoint y en el que se explica todas estas diferencias.

WSS 3.0 & MOSS: Algunos Tips & Tricks (II)

Hace un par de semanas iniciábamos una serie de posts respecto a algunos trucos, y también buenas prácticas, a la hora de trabajar con WSS 3.0 & MOSS. En el primer post nos centrábamos en algunos trucos que habíamos aprendido en el CIIN a la hora trabajar con el modelo de objetos de Sharepoint.  La idea de este segundo post es  comentar la forma usual de utilizar algunos de los objetos clave de Sharepoint y también comentar algunos aspectos de planning a tener en cuenta a la hora de abordar un proyecto basado en WSS 3.0 o en su hermano mayor MOSS. Empecemos.

El modelo de objetos de WSS 3.0

Como muchos sabéis, el modelo de objetos de WSS 3.0 es bestial y ha experimentado muchos cambios con respecto a WSS 2.0:

  • EL modelo de objetos de administración se ha rehecho completamente.
  • Los objetos SPSite y SPItem se “han cambiado” a mejor, de manera que soporta no sólo items de lista, sino también documentos de una biblióteca de documentos y carpetas.
  • Cambios en la concepción de las web parts, aprovechando el trabajo hecho en ASP.NET 2.0

Pero, ¿Dónde están todos estos objetos? A nivel de ensamblado, se encuentran en Microsoft.Sharepoint.dll el cuál podéis localizar en el siguiente path de vuestra instalación de WSS 3.0 o MOSS:

C:Program FilesCommon FilesMicrosoft Sharedweb server extensions12ISAPI

Post_Tips_Tircks_II_1 Post_Tips_Tircks_II_2

¿Y qué puedo desarrollar en WSS 3.0? Pues como diría alguno: “de todo”. Y siendo serios, la respuesta sería:

  • Se puede desarrollar cualquier elemento propio de WSS 3.0: listas, librerías de documentos, content types,columnas, tipos de datos, etc.
  • Llamar a los servicios web de Sharepoint para interactuar con elementos del mismo. Ya vimos un ejemplo en un post previo.
  • Desarrollar assemblies específicos para crear manejadores de eventos, controles personalizados, user controls, etc.
  •  Crear ficheros XML para desplegar y crear features, archivos de definición de sitios, listas, etc.
  • Crear páginas ASPX renderizables.
  • Crear plantillas de workflow.
  • Personalización de sitios WSS 3.0: extensión de web parts existentes (mediante CAML, XSLT) o creando nuevas.
  • Crear aplicaciones Windows Forms, servicios windows o simplemente aplicaciones de consola que nos permitan enriquecer nuesras soluciones de Sharepoint.

Cómo en todo modelo de objetos, hablamos de jerarquías. En este post nos interesa la jerarquía de los objetos relativos a los conceptos de web application, site collection, site, lista y elemento de lista de Sharepoint pues son los elementos claves a la hora de estructurar una solución de Sharepoint. Justamente la jerarquía para estos objetos sigue la enumeración comentada:

Post_Tips_Tircks_II_3

Pero como hemos comentado, el modelo de objetos de Sharepoint permite desarrollar “casi de todo” y es realmente extenso (imaginad el de MOSS), y como muestra este fenómenal póster que mi compañero Ángel utiliza en sus charlas y cursos sobre desarrollo en plataforma Sharepoint:

Post_Tips_Tircks_II_4

Vista la teoría, vamos a pasar a la práctica.

Ejemplos de uso de los objetos SPSite, SPWeb, SPList,…

  • El objeto SPSite representa un Site Collection, y por lo tanto una jerarquía de sitio/s hijos. La formas más usuales de utilizar este objeto son las siguiente:

//Cuando se dispone del contexto
SPSite spSitio1 = SPContext.Current.Site;
//Cuando no se dispone del contexto
SPSite spSitio2 = new SPSite(@”
http://litwaredemo);

Ya hemos visto en otros posts (por ejemplo en este) que esta no es la única forma de utilizar un objeto SPSite, por ejemplo:

//Obteniendo el contexto dentro de una web part
SPSite spsSitio = SPControl.GetContextSite(this.Context);
//A partir del objeto SPWorkflowActivationProperties
SPSite site = new SPSite(workflowProperties.SiteId);

Y seguro que hay más formas de acceder a una colección de sitios.

  • El objeto SPWeb representa un sitio individual de Sharepoint. Como ocurría con SPSite, hay dos formas habituales de utilizar este objeto dependiendo de si se dispone del contexto de la web o no (en cuyo caso partimos de un objeto SPSite para acceder a un objeto SPWeb):

//Cuando se tiene el contexto
SPWeb spwWeb1 = SPContext.Current.Site;
//A través de un objeto SPSite
SPSite spSitio = SPContext.Current.Site;
SPWeb spwWeb2 = spSitio.RootWeb;
SPWeb spwWeb3 = spSitio.OpenWeb();
SPWeb spwWeb4 = spSitio.OpenWeb(“/Subisitio1”);

Como ocurría con SPSie, estas no son las únicas posibilidades de acceder a SPWeb. Por ejemplo, si estamos desarrollando un workflow de nuevo nos podemos aprovechar de los miembros del objeto SPWorkflowActivationProperties para poder instanciar un objeto SPWeb:

SPWeb web = site.OpenWeb(workflowProperties.WebId);
  • SPSite y SPWeb: Recorriendo los subisitios de un site collection…algo habitual es a partir de un cierto Site Collection listar todas las webs contendias:

SPWeb spwWeb1 = SPContext.Current.Site;
//Recorrer los subsitios de un Site Collection
foreach (SPWeb spwWeb in spSitio.AllWebs) { }
foreach (SPWeb spwWeb in spSitio.RootWeb.Webs) { }

  • SPList y SPListItem, modelan respectivamente listas (también bibliotecas de documentos) y elementos de una lista de WSS 3.0. Las formas de utilizar estos objetos son también variadas:
//A partir de un Guid único
SPSite spsSitio=SPContext.Current.Site;
SPWeb spwWeb = spsSitio.OpenWeb();
string sListId = Request.QueryString[“ListId”];
SPList splLista=spwWeb.Lists[new Guid(sListId)];
//Mediante el nombre de la lista
SPList splLista2=spwWeb.Lists[“Lista”];
//Mediante el objeto SPWorkflowActivationProperties

SPList splLista3 = spwWeb.Lists[workflowProperties.ListId];

Una lista está compuesta por elementos de lista, es decir, a nivel de objetos un objeto SPList es una colección de objetos SPListItem. Por lo tanto, podemos utilizar estos objetos a partir de recorrernos dicha colección o bien aprovechando alguno de los métodos que nos ofrece el objeto SPList:

//Recorriendo la colección de items de la lista
foreach (SPListItem spliItem in splListaDestino.Items) { }
//Utilizando el método GetItmById
SPListItem spliItem = splListaDestino.Items.GetItemById(Convert.ToInt32(iItemId));

Y hasta aquí algunas formas de utilizar los objetos más habituales de WSS 3.0 & MOSS en lo que se refiere al trabajo con site collections, sitios de un site collection, listas y elementos de listas. Ahora me gustaría comentar algunas cosas básicas de planning en base a la experiencia que estamos teniendo en los distintos proyectos de Sharepoint en los que estamos participando y teniendo en cuenta las recomendaciones que hace Microsoft.

Algunas cosas de planning: objetivos de la solución de sharepoint y elementos de la misma

Cuando afrontamos un proyecto de WSS 3.0 y / o MOSS, debemos preguntarnos una serie de aspectos (contestar a una especie de check list) que luego van a ser claves en la implementación final de nuestra solución. Como siempre, la clave está en seguir una cierta estructura en cuanto a que aspectos necesito determinar para ver el grado de complejidad de nuestro proyecto:

  • Lo primero y más importante es determinar el objetivo u objetivo de la solución a implementar con WSS 3.0 & MOSS:
    • Si se trata de modelar alguno de los escenarios estándar para los que está pensado WSS 3.0 & MOSS: Comunicación, Colaboración, Publicación, …. y por lo tanto podemos seguir el estándar y aprovechar la funcionalidad out-of-the-box que nos da, extendiendo aquellos elementos que sean necesarios.
    • O bien queremos aprovechar algunas de las capacidades de WSS 3.0 & MOSS, pero implementar una solución cuya concepción se sale de la filosofía de WSS 3.0 & MOSS…un ejemplo de esto lo tenéis en un post reciente de Patrick Tisseghem en el que nos comenta que Sharepoint no está pensado por ejemplo para almacenar datos relacionales.
  • ¿De qué entorno estamos hablando? Intranet, Extranet o Internet.
  • Determinados los objetivos de la solución a implementar y que se traduce en una enumeración de sites (bien site collections o bien subistios dentro de un site collection), el siguiente paso está en determinar que elementos de los ofrecidos por WSS 3.0 & MOSS vamos a utilizar en estos sitios: calendarios, blog, wiki, … y que requerimientos especiales tenemos y que no son cubiertos con elementos out-of-the-box: workflows personalizados, web parts, etc.
  • Para aprovechar la idea de reutilización, el siguiente paso sería determinar que contenidos son comunes a los distintos sitios que hemos identificado: workflows de aprobación, integración necesaria con sistemas LOB, etc.

Evidentemente, para “acertar bien” y automatizar estos puntos lo ideal es disponer de unas fichas de recogida de este tipo de información y que de un vistazo nos permitan comprender la naturaleza de nuestra solución, los elementos que la componen y los puntos comunes. En msdn ya tenenmos un montón de plantillas tipo que podemos utilizar o bien enriquecer para facilitarnos el diseño de una solución de Sharepoint…como ejemplo, estas son algunas de las hojas excel que hemos elaborado en el CIIN para esta labor.

Post_Tips_Tircks_II_5

¿Y que más hay que tener en cuenta en el plannig?…ufff, esa si que es la pregunta del millón! Pues muchas cosas que espero contaros más adelante: columnas de sitio necesarias, content types necesarios, nuevos tipos de datos, workflows, tipo de acceso de los usuarios, etc. Por eso hasta aquí lo que os quería comentar sobre aspectos de desarrollo en plataforma de Sharepoint y planning de soluciones. Lógicamente, en ambos casos hemos tocado una pequeña parte de lo mucho que se puede hablar. En futuros posts seguiremos contando cosas de desarrollo y de planning. Espero que el post os haya resultado interesante.

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


Retomando el clásico recopilatorio de recursos y enlaces que sobre WSS 3.0 & MOSS venimos realizando con cierta regularidad, en esta ocasión destacamos los siguientes:


Documentación & Artículos



  • En este enlace podéis leeer parte de uno de los capítulos del libre Real World Sharepoint 2007. En cocnreto, está dedicado al desarrollo de web parts y ha sido escrito por Jan Tielens.

51-QamuZcXL__AA240_



Tips & Tricks



Recursos, Utilidades & Otros



Novedades



Y esto es todo en la última entrega del recopilatorio de recursos de WSS 3.0 & MOSS.

WSS 3.0 & MOSS: Algunos Tips & Tricks (I)

Normalmente cuando trabajamos con una cierta tecnología, sucede que en el aprendizaje de la misma vamos adquiriendo ciertas recetas que nos pueden salvar la vida, dar respuesta a comportamientos no esperados o simplemente arreglar lo que parecía que no fallaba. Lógicamente, WSS 3.0 y MOSS cumplen estas “máximas” y en el tiempo que llevamos trasteando con ellos hemos ido aprendiendo ciertos truquillos útiles que desde el CIIN nos gustaría compartir con el resto de la comunidad de desarrolladores (y especialmente la comunidad de desarrolladores, usuarios, simpatizanters, … de Sharepoint) Con este post pretendemos iniciar una serie de artículos en la que os dejaremos algunos pequeños trucos o consejos para resolver problemas que habitualmente os podéis encontrar en proyectos de WSS 3.0 & MOSS, así como afrontarlos de la mejor manera posible. Empecemos.


Copiado de attachments entre listas de Sharepoint


En uno de los posts publicados sobre Sharepoint, mostramos como copiar datos entre listas utilizando un workflow. Este código, ligeramente modificado y depurado lo utilizamos en uno de nuestros proyectos. Sin embargo, había un escenario en el que no funcionaba como es debido. El código original (sin la parte de recorrido de los elementos de la lista origen) referente a la copia de attachmentes desde un elemento de la lista origen a un elemento de la lista destino era:





//Elementos de WSS 3.0 necesariosSPList splListaOrigen = web.Lists[workflowProperties.ListId];SPList splListaDestino = web.Lists[LISTA_DESTINO];SPField spfCampo;SPFile spfAttachment;SPAttachmentCollection spacAttachments; //Items origen y destino SPListItem spliItemACrear = splListaDestino.Items.Add();SPListItem spliItemActual = workflowProperties.Item;//… spacAttachments = spliItemActual.Attachments; k = 0; for (k = 0; k <= spacAttachments.Count – 1; k++) { spfAttachment = web.GetFile(spliItemActual.Attachments.UrlPrefix + spacAttachments[k]);

spliItemACrear.Attachments.Add(spfAttachment.Name, spfAttachment.OpenBinary());


}


Básicamente, para poder copiar los attachments necesitamos un objeto de tipo SPAttachmentCollection que inicializamos con los attachments asociados al item a copiar. Luego por cada attachment tenemos que realizar un copiado “físico” en el elemento de la lista destino para lo que necesitamos un objeto de tipo SPFile que inicializamos con el attachment en cuestión y que especificamos a partir de construir su path web (mediante la propiedad UrlPrefix de la propiedad Attachment de SPListItem y que contiene la colección de attachments del elemento de la lista) y el attachment correspondiente (para cada iteracción del bucle). Luego utilizando el método Add() de la propiedad Attachment añadimos el attachment en cuestión copiandolo en modo binario. Hasta aquí todo bien y el código funciona perfectamente para copiar elementos con attachemtns vinculados entre listas de un mismo site collection, entre listas de sites collections diferentes dentro de una misma web application, o entre listas pertenecientes a site collections de web applications diferentes. Ahora bien, hay un escenario en el que si se copian todas las propiedades de un elemento de una lista a otra, pero no los attachments asociados…¿sabéis cuál es el escenario que provoca el error?…pues uno muy común en proyectos de WSS 3.0 / MOSS: extender una Web Application (es decir, crear una réplica, con lo que si creamos un site collection en una de las web application se creará uno idéntico en la web application extendida) para implementar una solución basada en Sharepoint en la que tengamos varios modelos de autenticación.


Post_Tips_WSS_MOSS_1


Post_Tips_WSS_MOSS_2


Os preguntaréis cuál es el problema, y este no es otro que el path web que estamos utilizando para especificar el attachment a copiar es absoluto, lo que en un escenario en el que tenemos una aplicación web extendida producirá un error en la parte de la url que identifica la web application y que es diferente de la web application extendida, por lo que al copiar un item de una lista a otra los attachments no serán copiados. ¿Y la solución? Pues, y como ocurre cuando trabajamos con ficheros (buena práctica por toro lado), consiste en trabajar con paths relativos. Para el caso planteado en el post original en el que los items se pasaban de una lista a otra mediante un workflow (en negrita las diferencias):





for (k = 0; k <= spacAttachments.Count – 1; k++) {                                                               //Url tipo: /Lists/Solicitudes de Actuacin/Attachments/8///string sPath = spliItemActual.Attachments.UrlPrefix + spacAttachments[k];                 string sPath = workflowProperties.ListUrl + ATTACHMENTS_EXPRESSION + spliItemActual[ID_LISTA_FIELD] +PATH_SEPARATOR + spacAttachments[k];spfAttachment = web.GetFile(sPath)

spliItemACrear.Attachments.Add(spfAttachment.Name, spfAttachment.OpenBinary());

}

Como vemos, en lugar de utilizar un path web absoluto utilizamos uno relativo utilizando la propiedad ListUrl del objeto workflowProperties (y que contiene las propiedades de inicio del workflow, incluido el propio ítem de la lista que ha motivado el lanzamiento del workflow), le añadimos el identificador del elemento al que pertenece el attachment y finalmente el nombre del attachment concreto.


Listar los documentos check-out de una biblioteca utilizando CAML


Para los profanos en CAML, o Collaborative Application Markup Language, es un lenguaje basado en XML muy usado para construir y customizar sitios de Sharepoint. De hecho, muchas de las web parts de Sharpoint lo utilizan para mostrar datos, siendo el ejemplo quizás más claro la ListViewWebPart. Aparte de su utilidad para construir y customizar sitios de Sharepoint (lo que puede ser bastante infernal como nos comentaba Carlos Segura), podemos utilizar CAML para consultar información de listas de Sharepoint utilizando el objeto SPQuery que nos permite realizar consultas a listas y bibliotecas de Sharepoint aplicando filtros de selección. Por ejemplo, para consultar los documentos checkout de una cierta biblioteca:





            SPSite spSitio = new SPSite(“http://litwaredemo/sites/Desarrollo/”);            SPWeb spwWeb = spSitio.OpenWeb();            SPList splCalendario=spwWeb.Lists[“Calendario”];             string sFechaActual = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Today);                        string sConsulta = “<OrderBy><FieldRef Name=’Title’/></OrderBy>” +                                “<Where><Geq><FieldRef Name=’EventDate’/>” +                                “<Value Type=’DateTime’>” + sFechaActual +                                 “</Value></Geq></Where>”;             SPQuery spqConsulta = new SPQuery();            spqConsulta.Query = sConsulta;             SPListItemCollection splicEventosCalendario =

                                 splCalendario.GetItems(spqConsulta);


En este ejemplo estamos consultando todos los eventos de una lista de tipo Calendar en la que el campo EventDate coincide con la fecha actual. La forma de operación de la consulta es similar a lo que conocemos en un acceso tradicional a datos:



  • Definimos la consulta “pegada” en código.
  • Creamos un objeto SPQuery y especificamos a través de la propiedad Query que la consulta sea la indicada.
  • Asignamos a un objeto de tipo SPListItemCollectio el resultado de ejecutar la consulta CAML sobre la lista Calendario a través del método GetItems().

Y hasta aquí llega el primer post de truquillos y recetas a la hora de trabajar con WSS 3.0 & MOSS. Espero que os resulte interesante.

Windows Live Translator Beta

Microsoft acaba de lanzar la primera versión beta de su propio servicio de traducción. Cómo se comenta en este enlace, el servicio accesible en la web a través del enlace  Windows Live Translator permite de momento traducir textos de una longitud de 500 palabras o bien páginas web completas. De momento se dispone de traducción entre los siguientes idiomas:

  • De Inglés a Alemán, Holandés, Francés, Español. Portugués, Itailiano. Coreano, Chino, Japonés y Ruso.
  • De cada uno de estos idiomas a Inglés.

Windows_Live_Transalator_Beta2

Como se comenta en la noticia (por cierto, aparecida en los blogs de Google), para la mayoría de las traducciones Microsoft utiliza el servicio de traducción de Systran, que permite también realizar traducciones online (también hay disponibles versiones de pago). Además, ofrece la posibilidad de identificar si el texto está relacionado con el mundo de la informática para usar en este caso un sistema de traducción desarrollado por Microsoft (esta opción sólo está disponible para traducir de Inglés a otros idiomas, pero no a la inversa).

Windows_Live_Transalator_Beta

Habrá que estar atentos a la evolución de este traductor online que parece que se integrará con Windows Live Search.

Visual Studio 2008 Beta2: Realizando Consultas con LINQ (I)

Hacía unos meses que tenía un poco olvidado a LINQ (en concreto a LINQ To SQL) y también la máquina virtual de Visual Studio 2008 Beta2 (en este caso ha estadp en el olvidomenos tiempo), asique ayer después de verme un video de como interactuar con una BD SQL Server mediante LINQ To SQL y con VB.NET me decidí a comenzar una serie de posts en las que mostrar aspectos de LINQ que ya comenté en un post prevío, y ya de paso refrescar algunas de las novedades que habréis leido / experimentado (sobre todo en el blog de Bruno) con Visual Studio 2008. También y siguiendo con el llamamiento de Miguel LLopis, os animo a que experimentéis y probéis  LINQ y las innovaciones en el lenguaje que vendrán con las nuevas versiones de C# y VB.NET.

En este post os voy a mostrar como de manera sencilla podemos definir un modelo de entidades con el OR Designer de LINQ sin más que arrastrar las tablas que nos interesen de una BD SQL Server a la superficie de diseño típica de Visual Studio.  Esta funcionalidad ya la teníamos con la primera preview de LINQ (mayo del año pasado) tal y como vimos en este post. Algunos cambios que aparecen en el OR Designer son referentes a los archivos que se generan: un archivo .layout que es justo el modelo creado que estamos visualizando y el típico archivo .designer.cs en el que encontraremos todo el código que Visual Studio autogenera para crear el modelo de entidades. Empecemos

Inspeccionando el modelo /fuente de datos subyacente

El primer paso antes de abrir Visual Studio 2008 Beta2 es tener claro cómo es el modelo de datos con el que vamos a operar. LINQ cambia la forma en que hasta ahora accediamos a los datos, pasamos de crear consultas SQL “peagadas” en código o en procedimientos almacenados a definir consultas integradas e el lenguaje. Sin embargo, a la hora de crear una aplicación de acceso a datos con o sin LINQ, lo primero es tener claro el modelo de datos que hay por debajo. Para este primer ejemplo he creado una sencilla base de datos (BD) con tres tablas relacionadas. El diagrama entidad relación es el siguiente:

Post_LINQ_VisualStudio2008_B2 

Creando el proyecto de demo de LINQ To SQL

Una vez que tenemos claro como es el modelo de datos, ya podemos irnos a Visual Studio 2008. Como siempre en un proyecto de Visual Studio, lo primero es crear nuestro proyecto. En este caso he optado por una aplicación Windows Forms, y en este primer punto ya tenemos una de las novedades de Visual Studio 2008: framework multitargeting, es decir, podemos escoger en base a que versión de .NET Framework implementar nuestras aplicaciones:

Post_LINQ_VisualStudio2008_B2_2

Cómo véis, las versiones de .NET Framework soportadas son la 2.0, la 3.0 y la 3.5, pero no las previas (seguro que es una pregunta que nos van a hacer mucho). También cuanto más alta es la versión, más plantillas de proyecto vamos a tener puesto que la filosifía que se sigue es continuar con lo anterior y añadir lo nuevo (así, en la versión 3.5 tenemos plantillas para crear actividades WCF para utilizar en nuestros workflows). En este caso, la versión de framework que hemos de utilizar es la 3.5 pues es la que incluye la infraestructura de LINQ.

Inspeccionando los elementos del proyecto

Una vez creado el proyecto de Windows Forms para .NET Framework 3.0, resulta interesante inspeccionar que “añadidos” tenemos en cuanto a referencias y espacios de nombres utilizados por el archivo .cs asociado al formulario.

Post_LINQ_VisualStudio2008_B2_3_1

Como vemos, en el archivo .cs ya se añade directamente el espacio System.Linq que nos da el acceso a toda la infraestructura de LINQ para definir consultas integradas en el lenguaje. En cuanto a referencias “novedosas” añadidas al proyecto se ha añadido las siguientes: System.Xml, y System.Xml.Linq con el objeto de poder utilizar la nueva forma de trabajar con XML que también ha venido con el proyecto LINQ.

Creando el modelo de entidades

El sigueinte paso (fundamental) es definir el modelo de entidades. Para ello, añadimos al proyecto un nuevo elemento de tipo LINQ To SQL Classes (novedad) de manera que se visualizará la típica superficie de diseño (este es el OR Designer) en la que vamos a definir el modelo de entidades a partir de arrastrar las tablas que nos interesen de la BD con la que vamos a trabajar:

Post_LINQ_VisualStudioOrcas_3_2 Post_LINQ_VisualStudioOrcas_4

Para los que estáis acostumbrados a trabajar con ADO.NET y datasets tipados, el resultado final os resultará familiar puesto que lo que estamos teniendo es una representación de nuestro modelo de datos a través de las correspondientes entidades y con las mismas relaciones que tengamos a nivel de la BD. Si inspeccionamos el archivo .designer.cs que se genera a partir del modelo, veremos que tenemos toda la infraestructura necesaria para trabaja con él y realizar la interactuación con la BD subyacente:

  • La clase DataContext, que como vimos es el que se encarga, entre otras funciones, de realizar la conexión a la BD subyacente y realizar el proceso de “traducción” de las consultas integradas en el lenguaje a las correspondientes instrucciones T-SQL
  • Una clase por cada una de las entidades que hemos “pintado” en el modelo. Para cada clase se generarán los atributos correspondientes a partir de realizar el correspondiente mapeo con las columnas y relaciones que tenemos a nivel de la BD.
  • Para interactúar con cada entidad, se generarán los correspondientes métodos de insercción, borrado, y actualización de datos.
  •  …

Post_LINQ_VisualStudioOrcas_8

Diseño del formulario

Esta paso es, para este ejemplo, el más sencillo. El formulario a diseñar mostrará un listado de datos recogidos de las tres tablas de nuestra BD y permitirá navegar por los mismos. Por lo tanto, necesitaremos un control de tipo DataGridView, un control de tipo BindingNavigator y su correspondiente BindingSource…con seleccionar, arrastrar y soltar listo:

Post_LINQ_VisualStudioOrcas_9

Programando la lógica del formulario

Una vez completados los pasos anteriores, ya estamos listos para definir la lógica asociada al formulario. Lo primero es instanciar un objeto DataContext de acuerdo a nuestro modelo de entidades para poder realizar operaciones contra la BD:

ModeloObjetosDataContext BD = new ModeloObjetosDataContext();

Una vez que ya tenemos establecido el contexto de datos, ya podemos emepezar a crear consultas utilizando LINQ. En este caso, la consulta que vamos a realizar se debería corresponder con la siguiente sentencia T-SQL:

select  c.sNombreCliente,c.sApellidosCliente,c.sCiudadCliente,
    v.sMarca,v.sModelo,ve.iKilometros
    from MD_Clientes C
    inner join MD_ClienteVehiculo ve on
    ve.ID_Cliente = c.ID_Cliente
    inner join MD_Vehiculos v on
    v.ID_Vehiculo=ve.ID_Vehiculo
    order by c.sCiudadCliente asc

Post_LINQ_VisualStudioOrcas_9_1

A partir de esta consulta, empezamos la traducción a LINQ. Lo primero es definirnos un tipo var en el que volcaremos la estructura de datos devuelta. Ya comentamos que es una innovación en el lenguaje que nos permite declarar tipos de manera ímplicita, es decir, sin especificarlo (siendo el compilador el que en tiempo de ejecución se encargue de determinar el tipo). A este tipo le asignamos la consulta a realizar…algo con lo que ya viene LINQ en Visual Studio 2008 Beta2 y que no teníamos con la preview de mayo de 2006 es el soporte de intellisense tanto para definir tipos ímplictios como para crear las consultas integradas en el lenguaje:

Post_LINQ_VisualStudioOrcas_9_2 Post_LINQ_VisualStudioOrcas_9_3

Con estas facilidades y conociendo como se definen las consultas integradas en el lenguaje con LINQ, “traducir” la consulta T-SQL anterior es bastante sencillo:

var clientes =
    from c in BD.MD_Clientes
    join ve in BD.MD_ClienteVehiculos on
    c.ID_Cliente equals ve.ID_Cliente
    join v in BD.MD_Vehiculos on
    ve.ID_Vehiculo equals v.ID_Vehiculo
    orderby c.sCiudadCliente ascending
    select new {c.sNombreCliente,c.sApellidosCliente,c.sCiudadCliente, v.sMarca, v.sModelo, ve.iKilometros};

Sin más, no tenemos más que forzar a que la consulta se ejecute vinculanto el tipo var con el control de datos que queramos (en este caso el BindingSource), configurar el resto de controles para que utilien este último, y añadir a nuestro código BD.Log= Console.Out para ver que comandos T-SQL se están enviando a la BD a través del objeto DataContext:

this.bindingSource1.DataSource = clientes;
this.dataGridView1.DataSource = this.bindingSource1;
this.bindingNavigator1.BindingSource = this.bindingSource1; 
     

Post_LINQ_VisualStudio2008_B2_10

Bueno, pues como cabía el resultado es el mismo y la sentencia T-SQL que se envía a la BD es muy similar (con un estilo más depurado diria yo) a la que nos planteamos inicialmente.

Entendiendo la ejecución de la consulta LINQ

Finalmente, y aunque ya lo comenté en el primer post que hicimos sobre LINQ, vamos a ver cuál es el punto en que se ejecuta realmente la consulta. A primera vista, cabe pensar que esta se ejecuta en el momento en el que se define. Sin embargo, esto no es así. La consulta se ejecuta realmente contra la BD en el momento en el que se va a utilizar su resultado, es decir, en el momento en el que vinculamos el tipo var con el control BindingSource. Veamos que esto sucede de esta forma ejecutando el código paso a paso y comprobando que salida tenemos en la consola de salida de Visual Studio:

Post_LINQ_VisualStudio2008_B2_11

Luego, cuando llegamos al punto de ruptura y ejecutamos el paso siguiente es el momento en el que la sentencia T-SQL se envía la BD y el resultado se vincula con el control BindingSource. Se está utilizando lo que en LINQ se conoce como ejecución diferida de consultas, es decir, estas se ejecutan en el momento en el que se va a hacer uso efectivo de las mismas.

Y hasta aquí llega el primer post de LINQ en Visual Studio 2008. Espero que os haya parecido interesante y que os animéis a creaer consultas con LINQ. Desde luego, para alguien acostrumbrado a escribir consultas en T-SQL, traducirlas a LINQ es realmente sencillo