LINQ to SQL (SQL compaq también existe!)

sqlserver2008logo

Esta mañana mi colega de penurias Toni Sala me preguntaba acerca de las posibilidades de usar LINQ to SQL con bases de datos SQL Compaq. Efectivamente, se puede hacer, es algo que probé en su momento y no había utilizado más. Sin embargo, lo que si que recordaba era que no es tan evidente como con sus hermanos mayores.

Bueno, al lío. Para este ejemplo vamos a usar la BD de ejemplo Northwind.sdf que instala Visual Studio 2008 (en mi caso la tengo ubicada en ‘C:Archivos de programaMicrosoft SQL Server Compact Editionv3.5Samples’).

Una vez creado el proyecto de ejemplo (en mi caso lo llamaré ‘SqlCompaqLINQ’), creamos una carpeta ‘Data’ dentro de nuestro proyecto y agregamos la BD a nuestro proyecto mediante ‘Project/Add existing Item’:

SqlCompaqLINQPE SqlCompaqLINQAddDB

Hasta aquí todo normal, pero la diferencia de SQlCompaq respecto a sus hermanos mayores está en que si ahora creamos un DataContext e intentamos arrastrar una tabla sobre él, aparecerá un mensaje de error un poco descorazonador:

SqlCompaqLINQError

No pasa nada, para estos casos podemos ir directamente a la herramienta SqlMetal (ya sabéis lo del poder del metal :-P), y generar el correspondiente fichero DBML mediante la línea de comandos. Para ello abrimos la consola de Visual Studio y ejecutamos el siguiente comando (desde nuestra carpeta ‘Data’):

SqlMetal.exe Northwind.sdf /dbml:NorthwindCE.dbml

Esto generará el diseñador con las clases correspondientes a las tablas de la BD de SQL Compaq, que a continuación agegaremos a nuestro proyecto también mediante ‘Project/Add existing Item’:

SqlCompaqLINQDataContext

Ahora basta con crear una instancia del diseñador, generar nuestra instrucción LINQ to SQL y ¡a jugar!:

using SqlCompaqLINQ.Data;
...
string path = "Data Source=|DataDirectory|\Data\Northwind.sdf";
using(Northwind dc = new Northwind(path))
{
    var customers = from c in dc.Customers
                    orderby c.CompanyName
                    select c;
    listBox1.DataSource = customers.ToList();
    listBox1.DisplayMember = "CompanyName";
    listBox1.ValueMember = "CustomerID";
}

Un saludo desde Andorra,

SR-71 Blackbird, un sueño hecho realidad

photo99Recuerdo que cuando tenía unos 10 añitos, quería ser piloto de cazas. Me pasaba tardes enteras mirando colecciones de cromos, y me compraba todas las revistas de aviones que me permitía mi escasa asignación semanal. Y soñaba, como sueñan todos los niños en cumplir algún día mis sueños…

De entre todos los aviones habidos y por haber, había uno que era mi favorito: El Lockheed SR-71Blackbird. Era precioso, muy avanzado para su tiempo, y su diseño era genial, simplemente una obra de arte. Más bien parecía una nave espacial antes que un avión, y eso para alguien que se crió con Star-Wars era toda una tentación.

En fin, a la vista está que mi sueño se quedó en eso… un sueño. Pero da igual, estoy seguro que muchos de nosotros tenemos algún sueño que no hemos podido cumplir. Aunque esa es otra historia, tampoco puedo quejarme ya que la vida me ha tratado bien.

Sin embargo, esta mañana mientras estaba buscando unas viejas fotos, me he topado con una serie de fotos que me han hecho recordar un momento que para mí fue muy especial. Fue en 2005, en el que fue mi primer MVP Summit.

Después de tres días de conferencias, sesiones, eventos, comidas y alguna salida nocturna por las calles de Seattle, unos cuantos de nosotros decidimos escaparnos al mueso de la Boeing. Era una pequeña excursión en la que aprovecharíamos para ir a comprar a algún centro comercial y yo aprovecharía para poder ver algún avión.

Pero allí, para mi sorpresa me encontré con que en mitad de un hangar enorme había un SR-71. No os cuento lo que fue poder verlo y tocarlo (aunque estaba prohibido :-P). Pude observar los motores con todo detalle, subir en una réplica de la cabina, y pasearme por debajo como en su día hicieron Clint Eastwood y Tommy Lee Jones en Space Comwoys. De esa película recuerdo una frase que dice que “el Blackbird cuando está posado en tierra es como un ladrillo, feo y hasta gotea combustible, pero que cuando se pone a Mach 3 sus juntas se cierran, todo encaja perfectamente y se convierte en una máquina perfecta”.

photo97 photo98 

 photo102 photo103

En fin, fue una sensación muy especial… Casi llego a considerar cumplido mi sueño.

Hablando de sueños. Recuerdas alguno de tus sueños de niño que no hayas podido cumplir?

Un saludo desde Andorra,

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (IV)

Entradas anteriores de la serie:

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (I)

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (II)

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (III)


bendervitruvio

He estado un par de días sin poder continuar con la serie, pero es que el trabajo aprieta y no siempre nos podemos dedicar a lo que más nos gusta…

Recapitulando: Cosas que necesitamos para nuestro add-in:

  • Cómo crear un complemento para Office (VSTO). visto en el post anterior.
  • Cómo registrar acciones en los menús de la aplicación host (Outlook). Lo veremos ahora.
  • Cómo conectar con un servidor MOSS/WSS con diferentes credenciales de usuario (System.Net.NetworkCredential) Esto también lo veremos ahora.
  • Cómo acceder a los sitios y listas de un site de MOSS/WSS (servicios Web de SharePoint). visto en el post anterior.
  • Cómo interpretar la información XML devuelta por los servicios (LINQ to XML). Y esto también lo veremos ahora.
  • El resto de cosas las veremos en los próximos días…

Hoy nos centraremos en mostrar cómo agregar opciones a los menús de Outlook (para lanzar nuestras acciones personalizadas), ver cómo conectar con un sitio de SharePoint con las credenciales predeterminadas, o bien proporcionando un usuario y password. Y además veremos cómo interpretar el resultado devuelto por los servicios Web, ya que el usar LINQ to XML va a facilitarnos en mucho la tarea de lidiar con XML puro y duro.

Demos un vistazo al futuro, a lo que va a ser este Add-In (solo Bender puede viajar al futuro):

1 – Una vez registradas nuestras propias acciones en el menú de Outlook, éstas permitirán guardar los elementos selecionados:

AddIn_Step1

2 – Aparecerá una ventana en la que podremos se leccionar la biblioteca de documentos y la carpeta destino:

 

 

AddIn_Step2

3 – Una vez seleccionada la carpeta, mostraremos una ventana de progreso en un hilo separado para que el usuario pueda seguir interactuando con Outlook:

AddIn_Step3

4 – Una vez terminado, si vamos a la biblioteca de documentos aparecerán los documentos (y más adelante también los metadatos):

AddIn_Step4

Vayamos por partes:

Registrar acciones en un menú de Outlook:

Registrar el menú es sencillo, sólo debemos modificar el código del evento ‘ItemContextMenuDisplay’ (como ya vimos en el post anterior), y llamar a un método ‘RegisterMenu’ que se encarga de agregar nuestras acciones al menú contextual de Outlook.

void Application_ItemContextMenuDisplay(
    Microsoft.Office.Core.CommandBar CommandBar, 
    Microsoft.Office.Interop.Outlook.Selection Selection)
{
    RegisterMenu(CommandBar, false);
}

 

 

 

void RegisterMenu(Microsoft.Office.Core.CommandBar CommandBar, bool IsFolder)
{
    Office.CommandBarPopup cmdSaveToMOSS = 
        (Office.CommandBarPopup)CommandBar.FindControl(
        missing, missing, "STSMOSS", missing, missing);
    if (cmdSaveToMOSS == null)
    {
        cmdSaveToMOSS = (Office.CommandBarPopup)CommandBar.Controls.Add(
                Office.MsoControlType.msoControlPopup, missing,
                missing, missing, false);
        if (cmdSaveToMOSS != null)
        {
            cmdSaveToMOSS.Caption = Properties.Resources.CONTEXT_MENU_CAPTION;
            cmdSaveToMOSS.Tag = "STMOSS";
            cmdSaveToMOSS.BeginGroup = true;
 
            Office.CommandBarButton btnSaveToMOSS =
                (Office.CommandBarButton)cmdSaveToMOSS.Controls.Add(
                Office.MsoControlType.msoControlButton, missing, missing, missing, missing);
 
            btnSaveToMOSS.Caption = Properties.Resources.CONTEXT_MENU_SENDBUTTON;
            btnSaveToMOSS.FaceId = 65;
            btnSaveToMOSS.Tag = IsFolder.ToString();
            btnSaveToMOSS.Style = MsoButtonStyle.msoButtonIconAndCaption;
            btnSaveToMOSS.Picture = getImage();
            btnSaveToMOSS.Click += new Microsoft.Office.Core.
                _CommandBarButtonEvents_ClickEventHandler(saveToMOSS_Click);  
            
            Office.CommandBarButton btnConfigurationMOSS =
                (Office.CommandBarButton)cmdSaveToMOSS.Controls.Add(
                Office.MsoControlType.msoControlButton, missing, missing, missing, missing);
 
            btnConfigurationMOSS.Caption = Properties.Resources.CONTEXT_MENU_CONFIGURATIONBUTTON;
            btnConfigurationMOSS.BeginGroup = true;
            btnConfigurationMOSS.Style = MsoButtonStyle.msoButtonIconAndCaption;
            btnConfigurationMOSS.Click += new Microsoft.Office.Core.
                _CommandBarButtonEvents_ClickEventHandler(configurationMOSS_Click);  
            
            cmdSaveToMOSS.Visible = true;
        }
    }
}

 

Este código crea un elemento menú y le agrega dos opciones (‘btnSaveToMOSS’ y ‘btnConfigurationMOSS’). A continuación establece sus propiedades y asigna los event handlers a sendas rutinas que se ejecutarán al pulsar sobre ellas.

void saveToMOSS_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref bool CancelDefault)
{     
    CancelDefault = true;
    MessageBox.Show("Save");
}
 
void configurationMOSS_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
    CancelDefault = true;
    MessageBox.Show("Config");
}

Conectar con un servidor MOSS/WSS con diferentes credenciales de usuario:

En algunas ocasiones tal vez nos interese conectar con un sitio de SharePoint y no hacer uso de las credenciales predeterminadas (por defecto el token del usuario de Windows). En estos casos, debemos hacer uso de la clase ‘System.Net.NetworkCredential’, pasando los valores de usuario y password (y opcionalmente dominio) para acceder al sitio. En este caso he creado unas sencillas funciones que devuelven un objeto de tipo ‘ICredentials’ que posteriormente usaremos en la propiedad ‘Credentials’ de los proxies de los servicios Web:

public static System.Net.ICredentials getCredentials()
{
    return System.Net.CredentialCache.DefaultCredentials;
}
 
public static System.Net.ICredentials getCredentials(string user, string password, string domain)
{
    return new System.Net.NetworkCredential(user, password, domain);
}

Interpretar el resultado devuelto por los servicios Web (LINQ to XML):

En el post anterior vimos que el resultado devuelto por los métodos de un servicio Web dista mucho de ser fácilmente interpretable, ya que nos devuelve un objeto de tipo XmlNode, de modo que debemos analizar el DOM para obtener el resultado deseado. En nuestro caso, vamos a realizar una llamada al método ‘GetWebCollection()’, que devuelve un XmlNode con los nombres de las webs (sites) de un sitio de SharePoint. Pero vamos a utilizar LINQ to XML para obtener sólo los elementos de un tipo determinado, y además vamos a obtener aquellos atributos que nos interesan. Y lo mejor es que todo se hace una sola sentencia:

public static List<SPSiteInfo> getSiteSubSites(websProxy.Webs sharePointWebs)
{
    try
    {
        XmlNode websResult = sharePointWebs.GetWebCollection();
        XDocument results = XDocument.Parse(websResult.OuterXml);
        XName name = XName.Get("Web", "http://schemas.microsoft.com/sharepoint/soap/");
        var webs = from item in results.Descendants(name)
                   select new SPSiteInfo
                       (
                       item.Attribute("Title").Value,
                       item.Attribute("Url").Value
                       );
        return webs.ToList();
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

A destacar en el código anterior el uso de un elemento XName para obtener sólo los elementos de tipo Web:

XName_Web

A continuación basta con seleccionar los atributos deseados de cada elemento XML (en nuestro caso título y url) e ir creando objetos que almacenaremos en una colección. Aquí utilizo una sencilla clase llamada ‘SPSiteInfo’ para devolver una lista genérica. Esta clase tiene sólo dos propiedades de tipo string (Title y URL) y un constructor en el que le pasamos ambos valores:

public class SPSiteInfo
{
    public string Title { get; set; }
    public string URL { get; set; }
 
    public SPSiteInfo()
    {
        //
    }
 
    public SPSiteInfo(string title, string url)
    {
        Title = title;
        URL = url;
    }
}

De este modo, ya tenemos una función que nos devuelve una colección de objetos ‘SPSiteInfo’. Emplearemos este mismo procedimiento para recuperar las bibliotecas de documentos de un sitio, las carpetas de una biblioteca de documentos, e incluso las columnas de una biblioteca de documentos.

Pero ello lo veremos en el próximo post, que hay que volver a las trincheras… :-)

PD – Os recuerdo que al final de la serie publicaré el código fuente del proyecto de ejemplo.

J*der que susto!

miedo

Viernes por la tarde, toda la oficina para nosotros.

Hoy tenemos planificada la actualización del domino principal 2003 a 2003 R2, algo trivial y que en teoría no debe llevarnos demasiado tiempo. De hecho no sería necesario que nos quedásemos más de uno pero hemos pensado en acabar pronto con esto e ir todos a tomar una cerveza 😛

Vamos al lío.

Procedemos a actualizar el esquema con el conocido adprep /forestprep y a continuación vamos a lanzar el asistente de instalación de Windows Server 2003 R2, cuando de pronto aparece un mensaje de error que nos impide continuar:

Otra aplicacion requiere que este equipo se reinicie. Bla, bla, bla…

Uhm… vaya, esto no debería pasar pero bueno, por si acaso vamos a reiniciar y volvemos a probar. Reiniciamos el equipo (menos mal que a esta hora ya no hay nadie trabajando, probamos otra vez y… lo mismo. Ups! Volvemos a reiniciar otra vez mientras se forman las primeras gotas de sudor y nada. Otra vez lo mismo.

Uy, uy, uy…

Mierda.

El pánico empieza a apoderarse de nosotros mientras empiezo a pensar que este mensaje ya lo he visto con anterioridad, aunque sin embargo no apareció en las pruebas de pre-producción. Intento recordar cuándo vi este mensaje y cómo lo resolví, pero no me acuerdo :-S

De pronto tengo una inspiración divina: Creo que ya se que pasa, y busco en en la kb de http://support.microsoft.com/ por incidencias con Microsoft Windows Installer. Afortunadamente no pasan ni dos minutos y ya he encontrado una entrada que tiene muy buena pinta.

El problema es que Microsoft Windows Installer determina que la entrada de registro PendingFileRenameOperations no está vacía, con lo que antes de iniciar cualquier instalación hay que revisar y limpiar (o renombrar) esta clave de registro.

Abro el registro, busco la clave y “oh sorpresa! oh dolor! oh campos de soledad, mustios collados…”, un fichero de la instalación del anvitirus. Pues nada, a la hoguera con él :-)

La solución consiste en:

  1. Cambiar manualmente el nombre de la entrada de registro PendingFileRenameOperations. Para ello, siga estos pasos:
    1. Haga clic en inicio y, a continuación, haga clic en Ejecutar .
    2. En el cuadro Abrir , escriba regedit y, a continuación, haga clic en ACEPTAR para iniciar el Editor del registro.
    3. En el Editor de Registro, busque y haga clic en la siguiente subclave del registro:

      HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession Manager

    4. En el nombre en el panel derecho del editor del registro, cambiar el nombre del PendingFileRenameOperations entrada del registro.
  2. Compruebe que la siguiente subclave del registro está vacía:

    HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRunOnce

  3. Compruebe que la siguiente subclave del registro está vacía:

    HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRunOnceEx

  4. Cierre el Editor del Registro y ejecutar de nuevo el programa de instalación (en nuestro caso Windows 2003 R2).

Diez minutos después ya hemos terminado y ahora escribo esta entrada por si a alguien le sucede lo mismo. Aunque el susto se lo llevará igual :-)

Saludos y buen fin de semana,

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (III)

Entradas anteriores de la serie:

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (I)

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (II)


 BenderDrinking

Bueno, vamos a empezar a trabajar en nuestro Add-In!

Aunque antes, una aclaración: Como la mayoría de vosotros ya sabéis, en realidad quién hace el trabajo sucio no soy yo. Yo sólo me llevo los millones y la fama, mientras que la ingrata tarea de picar código (que no gusta a nadie :-P) se la dejo a mi Bender. Efectivamente, acabáis de descubrir uno de los secretos mejor guardados: Detrás de un MVP siempre hay alguien haciendo el trabajo real mientras ellos se llevan el mérito… Esto ha sido así desde que el pionero Rubén Vigón enseñó a codificar a su gato con Visual Basic 3.0, y poco a poco la mayoría hemos ido ‘adoptando’ esta acertada filosofía, que en mi caso me ha permitido apartarme de estas tareas mundanas y dedicarme a mis viñedos y mi afición desmedida por la calceta.

Así que en cuanto le propuse la idea del Add-In a Bender, le pareció que debíamos ponernos a ello en seguida (seguramente animado por la visión de las 2 cajas de un chardonnay excelente que recibirá como compensación al terminar). De modo que vamos a empezar en seguida.

Nota: Al terminar la serie publicaré el proyecto de ejemplo con todo el código al completo.
Un poco de paciéncia porque lo voy a ir haciendo sobre la marcha, ok?

Creando un proyecto Add-In para Outlook 2007

Esta es la parte más sencilla, ya que con Visual Studio 2008 (supongo que todos lo tenéis actualizado con el SP1) se incorporan las plantillas básicas para crear un proyecto de este tipo. Basta con iniciar un proyecto nuevo, y dentro de la categoría ‘Office’ encontraréis las plantillas para la versión 2007.

OutlookAddInNewProject

Esto crea un proyecto C# con las referencias necesarias para ejecutarse como complemento de Outlook, y proporciona el esqueleto básico para interceptar los eventos que se producen al cargar y descargar nuestro complemento.

ProjectReferences

using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
 
namespace OutlookToMOSS
{
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
 
        }
 
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }
 
        #region VSTO generated code
 
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        
        #endregion
    }
}

Observar que hay una región de código generado por el diseñador, que es la encargada de suscribir los eventos ‘StartUp’ y ‘StartDown’. En estos eventos, posteriormente agregaremos el código para inicializar y destruir nuestras referencias a los servicios Web de SharePoint. Además para poder interactuar con Outlook interceptaremos además un par de eventos más llamados ‘ItemContextMenuDisplay’ y ’FolderContextMenuDisplay’, que se producen al mostrar los menús contextuales de Outlook (por ejemplo, al pulsar el botón derecho sobre una selección de elementos de correo).

Agregando referencias a los servicios Web de SharePoint

Lo primero es lo primero, así que ya que vamos a interactuar con SharePoint, vamos a agregar referencias Web a aquellos servicios que vamos a consumir. Aunque tenemos una lista de varios servicios Web, de entrada vamos a trabajar con estos dos, aunque probablemente añadiremos otros más adelante:

  • Webs Web Service: Para acceder a la colección de sitios Web de un sitio de SharePoint.
  • Lists Web Service: Para acceder a la colección de bibliotecas de documentos de un sitio.

Para crear la referencia debemos conocer la URL de nuestro SharePoint (por ejemplo http://moss). Y agregar una ‘Service Reference’ al proyecto. Esto mostrará el cuadro de diálogo para agregar servicios WCF, pero como en nuestro caso vamos a agregar una referencia a un servicio Web 2.0 hay que dar un rodeo, ir a la parte avanzada y especificar que queremos crear una ‘Web reference‘:

AddWebReference1

Pulsar en el botón para mostrar las características avanzadas:

AddWebReference2

Especificar que deseamos agregar una ‘Web reference’ y en la nueva ventana especificar la URL del servicio, que siempre sigue esta nomenclatura:

<URL Servidor SharePoint>/_vti_bin/<Nombre del servicio Web>

En nuestro caso:

http://moss/_vti_bin/Webs.asmx

http://moss/_vti_bin/Lists.asmx

Especificando el nombre (en mi caso tengo por costumbre llamarlos websProxy y listsProxy).

AddWebReference3

Una vez añadidas veremos que en el árbol del proyecto aparece un elemento llamado ‘Web References’ que contiene las dos referencias a los servicios Web.

Interceptando eventos de Outlook

Ahora, para hacerlo más interesante, antes de ejecutar vamos a interceptar el evento ‘ItemContextMenuDisplay’ que se produce cuando el usuario muestra el menú contextual de los elementos de correo (dicho de otro modo, selecciona uno o varios emails y pulsa botón derecho). Para ello modificaremos la sección generada por el diseñador, agergando la siguiente línea al método InternalStartUp():

this.Application.ItemContextMenuDisplay += 
    new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemContextMenuDisplayEventHandler(
    Application_ItemContextMenuDisplay);

 Y lógicamente ahora crearemos el método que será llamado al dispararse el evento:

 
        void Application_ItemContextMenuDisplay(
            Microsoft.Office.Core.CommandBar CommandBar, 
            Microsoft.Office.Interop.Outlook.Selection Selection)
        {
            websProxy.Webs sharePointWebs;
            sharePointWebs = new websProxy.Webs();
            sharePointWebs.Credentials = System.Net.CredentialCache.DefaultCredentials;
            XmlNode webs = sharePointWebs.GetWebCollection();
        }

Este código es provisional, pero nos servirá para ver como se debe llamar a un método de un servicio Web. Primeramente se declara y se crea el objeto, a continuación se especifican las credenciales (en este caso las predeterminadas) y a continuación se llama al método GetWebCollection(), el cual nos devuelve un objeto… “oh sorpresa! oh dolor! oh campos de soledad, mustios collados…”, un objeto de tipo XmlNode. Efectivamente, los servicios Web de SharePoint trabajan con XML a tutiplén, con lo cual ya te aviso de que si no te gusta trabajar con XML tienes dos opciones: Dejar ahora mismo de leer este artículo escrito por Bender y hacer como yo disfrutando la de vida alegre, o bien esperar al próximo post, en el que veremos como LINQ to XML puede hacernos la vida un poco más fácil.

Ahoravamos a establecer un punto de ruptura en la última línea de código para ver que retorna el método GetWebCollection().

Estamos listos para ejecutar?

Pues si, ahora vamos a probar que sucede cuando ejecutamos nuestro proyecto. Como es un Add-In de Outlook va a arrancar éste primero y cuando hagamos click con el botón derecho sobre un elemento de correo entrará en acción el depurador permitiéndonos inspeccionar el valor de la variable ‘webs’, el cual os muestro a continuación, para que os asusteis un poco (hacer click en la imagen para verla más grande):

XmlNode_webs

Mañana espero poder continuar con la serie. Y veremos cómo agregar elementos a los menús de Outlook, y cómo LINQ to XML nos va a permitir trabajar más cómodamente con los datos devueltos por los métodos de los servicios Web. Que todos sabemos de las bondades de XML, pero trabajar con atributos nunca resulta tan sencillo como trabajar con colecciones de objetos genéricos, verdad?

Pues eso, mañana más… que ahora me toca manicura y luego clase de tenis 😛

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (II)

Entradas anteriores de la serie:

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (I)


Vale, vamos a empezar a escribir la carta a los reyes magos:

Reyes-Magos

Queridos reyes magos,

Este año me he portado muy bien así que me pido un add-in para Outlook que sirva para guardar los correos en bibliotecas de documentos de SharePoint, y que tenga las siguientes cositas:

  • Que se integre con los menús de Outlook, para poder seleccionar varios correos y copiarlos a la biblioteca que yo elija.
  • Que funcione tanto para MOSS como para WSS, para poder guardar correos en un servidor WSS que tengo en hosting en USA.
  • Que permita cambiar la ubicación del servidor de SharePoint para poder guardar los correos en el que me interese.
  • Que permita cambiar las credenciales de usuario, para permitir conectarme a diferentes sitios.
  • Que se encargue de crear las columnas necesarias para guardar los metadatos del elementos de correo (De, Para, Asunto, Enviado).
  • Que cuando guardemos una cantidad importante de correos no detenga la ejecución de Outlook, y podamos seguir trabajando mientras éstos se copian.
  • Y un detalle importante: Que tenga control de versiones, por si guardo dos veces el mismo elemento que me mantenga un histórico.

Y para desarrollar algo así necesitaremos saber varias cosas, por ejemplo:

  • Cómo crear un complemento para Office (VSTO).
  • Cómo conectar con un servidor MOSS/WSS con diferentes credenciales de usuario (System.Net.NetworkCredential)
  • Cómo acceder a los sitios y listas de un site de MOSS/WSS (servicios Web de SharePoint).
  • Cómo interpretar la información XML devuelta por los servicios (LINQ to XML).
  • Cómo guardar un fichero en una biblioteca de documentos de SharePoint con control de versiones (DocLibHelper).
  • Cómo ejecutar distintos threads y mostrar el progreso (Callbacks).
  • Cómo distribuir nuestro complemento, creando un archivo MSI (Windows Installer packages).

Y seguramente me dejo unas cuantas cosillas… pero ya las iremos abordando a medida que nos las encontremos. Al fin y al cabo esto es un proyecto de ejemplo y personal, así que sintiéndolo mucho no voy a utilizar SCRUM 😉

Un saludo y mañana prometo empezar con el tema!

SharePoint 2007 + Outlook 2007: Guardar correos de forma masiva (I)

SharePointServices

Es obvio que SharePoint es uno de los mayores productos de Microsoft, y que ha supuesto una revolución en el entorno colaborativo empresarial. Hoy en día esta herramienta hace posible que la información fluya entre los integrantes de una organización, y eso ha aumentado mucho la productividad y los procesos de trabajo de la empresa, algo que siempre agradecen los gestores :-)

Es obvio también que una plataforma de este calibre tiene muchas cosas a mejorar, ya que es todavía un “recién nacido” (aunque lleve ya tres versiones como producto). De forma que hay unos cuantos huecos que deben rellenarse con horas de ardua programación… algo que desespera a más de uno. Mucha gente me pregunta “¿pero cómo es posible que esto no esté implementado?”, y mi respuesta acostumbra a ser “pueeees… no tengo ni idea chico, pero lo bueno es que disponemos de un modelo de objetos que hace posible que lo implementes tu mismo.”

La verdad es que es más que posible que muchas de estas pequeñas cositas se implementen en la futura y deseada siguiente versión (de la que muy pocos elegidos saben algo), pero hasta entonces nos encontramos con algunas cosas que hay que hacer ‘a mano’.

Precisamente la última con la que me he encontrado (para mi sorpresa) se trata de que la integración de Outlook 2007 con SharePoint 2007 no es todo lo buena que debería, o más bien que falta alguna característica que encuentro “básica”.

En este caso se trata de la clasificación de elementos de correo en bibliotecas de documentos de SharePoint. Sería estupendo poder clasificar nuestros correos en bibliotecas de documentos con un simple “Guardar como…”, pero esto sólo se puede realizar cuando guardamos los correos de forma individual, ya que deben guardarse como ficheros MSG. Resulta que por algún designio divino esta opción no está disponible cuando seleccionamos varios elementos, y claro, ya sabemos que no es una opción válida para un gestor que está muy ocupado intentando salvar el mundo 😉 y menos en los tiempos que corren, en los que hay que salir de esta crisis a golpe de reuniones de high-level y comités de dirección, y no estamos para dilapidar el tiempo en tareas repetitivas, verdad?

correo

Bueno, al grano que me estoy yendo… el tema es que como no he encontrado una forma de hacerlo, me he propuesto crear un add-in para Outlook, que permita guardar elementos de correo en bibliotecas de documentos de SharePoint. Y a medida que lo vaya desarrollando iré posteando algunas de las cosas interesantes de este desarrollo (cómo crear un proyecto de add-in para Outlook con VSTO, cómo interactuar con la aplicación host, acceder a los servicios Web de SharePoint, cómo distribuir el Add-In, etc). Y al final postear el código de ejemplo o crear un proyecto en codeplex para la comunidad. De este modo servirá de ejemplo (aunque sea malo :-P) y tal vez a alguien más podrá serle útil.

En el próximo post empezaremos a planificar el desarrollo. Saludos y hasta pronto,