Custom InfoPath Email Activity para Sharepoint Designer 2010.

por Mauricio Rodriguez  14. marzo 2012

Recientemente he finalizado, junto con el equipo de Sharepoint, un proyecto interesante en cuanto al nivel de personalización que el cliente exigía.

El requerimiento era crear un workflow de aprobación reusable para formularios de solicitud de empleo. Lo significativo de este workflow era que debía trabajar sin lista de tareas ( esencial en los workflows de aprobación de Sharepoint ) y con emails personalizados, los cuales debían llevar adjunto el formulario (hecho en InfoPath), de manera que los usuarios involucrados en el proceso de solicitud, puedan abrirlos desde Outlook y completarlos.

Desde el inicio pensamos en una Custom Activity que pueda cumplir con el requerimiento de envío de mails .

En esta oportunidad vamos a ver como crear una Custom Activity para enviar mails con formularios InfoPath adjuntos para poder usarla desde el Sharepoint Designer en el diseño de una solución.

1 - Creación de la estructura de la solución.

Para comenzar vamos a crear un Empty SharePoint Project en Visual Studio 2010.

Le damos nombre al proyecto y seleccionamos “Ok”. Se abrirá una ventana en la cual deberemos especificar el Servidor de Sharepoint donde se hará el deploy de la solución, y si lo queremos hacer como Sandboxed Solution o FarmSolution. En nuestro ejemplo vamos a usar una Farm Solution.

image

Finalizamos, y Visual Studio nos creará un proyecto en base al template Seleccionado que se verá como la siguiente imagen.

Vamos a modificar el nombre del archivo key.snk por el nombre de nuestro proyecto, en este caso VEMN.CustomActivity. Esto es mas que nada para mantener un orden y una correspondencia.

 

Una vez hecho esto, agregamos una Feature, le damos un nombre, siempre es preferible usar el mismo nombre del proyecto para mantener una coherencia.

image

Luego vamos a agregar una Sharepoint Mapped Folder. Nos paramos sobre el proyecto, Clik Derecho –> Add –> Sharepoint Mapped Folder. Es de vital importancia el siguiente paso ya que este cambia de acuerdo al lenguaje en que esté nuestro Sitio. Como el nuestro está inglés seleccionaremos la ruta …/TEMPLATE/1033/Workflow. En caso de que nuestro sitio este en Español debemos seleccionar el directorio 3082 o el código que le corresponda.

image

Esto mapea esta carpeta a nuestro proyecto en donde vamos a agregar un archivo xml que va a contener la metadata y las definiciones de parámetros de entrada y salida de nuestra Custom Activity. Este lo llamaremos con mismo nombre que el proyecto y la extensión se la cambiaremos de .xml a .actions, como se puede ver en la imagen siguiente.

image

 

2 - Definición del archivo ACTIONS

Definiremos a continuación, el archivo .actions que acabamos de agregar. Es importante tener en cuenta que este archivo es leído por el SPD para levantar nuestra custom activity y habilitarla en el menú Action. Por lo cual deberemos prestar mucha atención al momento de crearlo, para no tener problemas en la implementación.

Nuestro xml debe quedar con las siguiente estructura. Luego discutiremos sobre que es cada cosa:

   1: <WorkflowInfo Language="en-US">
   2:    <Actions Sequential="then" Parallel="and">
   3:       <Action Name="Send mail with attachment infopath form"
   4:            ClassName="VEMN.CustomActivity.SendMailActivity"
   5:            Assembly="VEMN.CustomActivity,Version=1.0.0.0,Culture=neutral,PublicKeyToken=7819e4834cee4b0e"
   6:            AppliesTo="all"
   7:            Category="Custom Actions">
   8:           <RuleDesigner Sentence="Send mail with this %1 attachment to %2. Use %3 like sender. >
   9:              <FieldBind Field="AttachmentFileName" Text="form (url)" DesignerType="TextArea" Id="1"/>
  10:              <FieldBind Field="To,CC,Subject,Body" Text="these user(s)" DesignerType="Email" Id="2"/>
  11:              <FieldBind Field="From" Text="this user" DesignerType="TextArea" Id="3"/>  
  12:           </RuleDesigner>
  13:           <Parameters>
  14:             <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />
  15:             <Parameter Name="__ListId" Type="System.String, mscorlib" Direction="In" />
  16:             <Parameter Name="__ListItem" Type="System.Int32, mscorlib" Direction="In" />
  17:             <Parameter Name="__ActivationProperties" Type="Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties, Microsoft.SharePoint" Direction="Out" />
  18:             <Parameter Name="AttachmentFileName" Type="System.String, mscorlib" Direction="In" />
  19:             <Parameter Name="To" Type="System.Collections.ArrayList, mscorlib" Direction="In" />
  20:             <Parameter Name="CC" Type="System.Collections.ArrayList, mscorlib" Direction="Optional" />
  21:             <Parameter Name="Subject" Type="System.String, mscorlib" Direction="In" />
  22:             <Parameter Name="Body" Type="System.String, mscorlib" Direction="Optional" />
  23:             <Parameter Name="From" Type="System.String, mscorlib" Direction="In" />
  24:          </Parameters>
  25:       </Action>
  26:    </Actions>
  27: </WorkflowInfo>

El nodo WorkflowInfo solo definimos el lenguaje del sitio en el cual vamos a utilizar nuestra funcionalidad. El nodo Actions define la forma en el texto se construye luego de la descripción de la acción en el diseñador del flujo de trabajo. Por ejemplo, en una acción secuencial seria algo así: “<actiondescription> then”.

Lo realmente interesante está en el nodo Action, en el, los atributos Name, ClassName, Assembly, ApplyTo and Category definen: el nombre de la acción en el Menú de Acciones (o Actions Menu), la Clase y el Assembly para el código, si se refiere a List Items , sólo documentos, o todos, y la categoría bajo la cual aparecerá listada nuestra Acción.

El nodo RuleDesigner específica el texto a mostrar y los parámetros de entrada. El atributo Sentence determina la sentencia que se mostrará en el Diseñador de workflows. Podemos especificar cada parámetro con un signo % seguido de un numero, por ejemplo 1, que apuntará al primer parámetro y así sucesivamente. Estos parámetros son referenciados por los FieldBind. El atributo text del mismo reemplazara a los % del Sentence. El atributo ID debe coincidir con el orden del parámetro.

Y por ultimo el nodo Parameters y sus hijos definen los parámetros que serán pasados a nuestra Custom Activity. Los nombres de los attibutos Field de los Nodos FieldBind deben coincidir exactamente con los atributos Name de los Nodos Parameters para que sean transferidos a nuestro código.

3 - Definición de nuestra clase principal.

Crearemos una clase que llamada SendMailActivity.cs o como quieran llamarla. La misma debe heredar de System.Workflow.ComponentModel.Activity (no olvidemos agregar la referencia a esta dll) la cual contiene un método llamado Execute que es el punto clave para nuestra Custom Activity que luego vamos a sobrescribir.

Ahora, definamos las propiedades en nuestra clase de modo que coincidan con lo que acabamos de establecer en el archivo .actions para que quede todo mapeado. Este mapeo se logra gracias al objeto DependencyProperty como veremos luego.

Al inicio nos ocuparemos de definir las propiedades del WorkflowContext y luego las personalizadas.

   1: #region [ Workflow Context Properties ]
   2:  
   3: public static DependencyProperty __ContextProperty = DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(SendMailActivity));
   4:  
   5: [ValidationOption(ValidationOption.Required)]
   6: public WorkflowContext __Context
   7: {
   8:     get
   9:     {
  10:         return ((WorkflowContext)(base.GetValue(__ContextProperty)));
  11:     }
  12:     set
  13:     {
  14:         base.SetValue(__ContextProperty, value);
  15:     }
  16: }
  17:  
  18: public static DependencyProperty __ListIdProperty = DependencyProperty.Register("__ListId", typeof(string), typeof(SendMailActivity));
  19:  
  20: [ValidationOption(ValidationOption.Required)]
  21: public string __ListId
  22: {
  23:     get
  24:     {
  25:         return ((string)(base.GetValue(__ListIdProperty)));
  26:     }
  27:     set
  28:     {
  29:         base.SetValue(__ListIdProperty, value);
  30:     }
  31: }
  32:  
  33: public static DependencyProperty __ListItemProperty = DependencyProperty.Register("__ListItem", typeof(int), typeof(SendMailActivity));
  34:  
  35: [ValidationOption(ValidationOption.Required)]
  36: public int __ListItem
  37: {
  38:     get
  39:     {
  40:         return ((int)(base.GetValue(__ListItemProperty)));
  41:     }
  42:     set
  43:     {
  44:         base.SetValue(__ListItemProperty, value);
  45:     }
  46: }
  47:  
  48: public static DependencyProperty __ActivationPropertiesProperty = DependencyProperty.Register("__ActivationProperties", typeof(SPWorkflowActivationProperties), typeof(SendMailActivity));
  49:  
  50: [ValidationOption(ValidationOption.Required)]
  51: public SPWorkflowActivationProperties __ActivationProperties
  52: {
  53:     get
  54:     {
  55:         return (SPWorkflowActivationProperties)base.GetValue(__ActivationPropertiesProperty);
  56:     }
  57:     set
  58:     {
  59:         base.SetValue(__ActivationPropertiesProperty, value);
  60:     }
  61: }
  62:  
  63: #endregion [ Workflow Context Properties ]

Pasemos ahora, a crear las propiedades personalizadas.

   1: #region [ Custom Workflow Properties ]
   2:  
   3: public static DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(ArrayList), typeof(SendMailActivity));
   4:  
   5: [ValidationOption(ValidationOption.Required)]
   6: public ArrayList To
   7: {
   8:     get
   9:     {
  10:         return ((ArrayList)(base.GetValue(SendMailActivity.ToProperty)));
  11:     }
  12:     set
  13:     {
  14:         base.SetValue(SendMailActivity.ToProperty, value);
  15:     }
  16: }
  17:  
  18: public static DependencyProperty CCProperty = DependencyProperty.Register("CC", typeof(ArrayList), typeof(SendMailActivity));
  19:  
  20: [ValidationOption(ValidationOption.Optional)]
  21: public ArrayList CC
  22: {
  23:     get
  24:     {
  25:         return ((ArrayList)(base.GetValue(SendMailActivity.CCProperty)));
  26:     }
  27:     set
  28:     {
  29:         base.SetValue(SendMailActivity.CCProperty, value);
  30:     }
  31: }
  32:  
  33: public static DependencyProperty SubjectProperty = DependencyProperty.Register("Subject", typeof(string), typeof(SendMailActivity));
  34:  
  35: [ValidationOption(ValidationOption.Required)]
  36: public string Subject
  37: {
  38:     get
  39:     {
  40:         return ((string)(base.GetValue(SendMailActivity.SubjectProperty)));
  41:     }
  42:     set
  43:     {
  44:         base.SetValue(SendMailActivity.SubjectProperty, value);
  45:     }
  46: }
  47:  
  48: public static DependencyProperty BodyProperty = DependencyProperty.Register("Body", typeof(string), typeof(SendMailActivity));
  49:  
  50: [ValidationOption(ValidationOption.Optional)]
  51: public string Body
  52: {
  53:     get
  54:     {
  55:         return ((string)(base.GetValue(SendMailActivity.BodyProperty)));
  56:     }
  57:     set
  58:     {
  59:         base.SetValue(SendMailActivity.BodyProperty, value);
  60:     }
  61: }
  62:  
  63: public static DependencyProperty AttachmentFileNameProperty = DependencyProperty.Register("AttachmentFileName", typeof(string), typeof(SendMailActivity));
  64:  
  65: [ValidationOption(ValidationOption.Required)]
  66: public string AttachmentFileName
  67: {
  68:     get
  69:     {
  70:         return ((string)(base.GetValue(AttachmentFileNameProperty)));
  71:     }
  72:     set
  73:     {
  74:         base.SetValue(AttachmentFileNameProperty, value);
  75:     }
  76: }
  77:  
  78: public static DependencyProperty FromProperty = DependencyProperty.Register("From", typeof(string), typeof(SendMailActivity));
  79:  
  80: [ValidationOption(ValidationOption.Required)]
  81: public string From
  82: {
  83:     get
  84:     {
  85:         return ((string)(base.GetValue(SendMailActivity.FromProperty)));
  86:     }
  87:     set
  88:     {
  89:         base.SetValue(SendMailActivity.FromProperty, value);
  90:     }
  91: }
  92:  
  93:  
  94: #endregion [ Custom Workflow Properties ]

Ahora bien,  podemos avanzar en la creación de nuestro método. Aquí explicaré con más detalle la solución.

Lo que necesitabamos hacer para poder adjuntar el formulario infopath a un email era acceder físicamente al mismo. El problema de esto era que no tenia forma de obtener la referencia hacia ninguna ruta “física” del item (formulario), pero sí, por medio del contexto del Workflow, podía saber cual era su ubicación lógica (Url) desde la propiedad CurrentItemUrl. Aquí llegamos al tema más interesante de este post.

Primer paso importante:

Como podrán ver luego, se usó la url del ítem actual para crear un WebRequest a partir del cual podía obtener un ResponseStream. Algo bastante sugestivo, y algo que no podemos olvidar de hacer al crear el Request para un formulario InfoPath, es enviar un parámetro en el header del mensaje de modo que cuando se ejecute, este no sea redireccionado a FormServer.aspx (redirección por default cuando accedemos a un archivo infopath). El modo de enviar este parámetro es el siguiente:  myRequest.Headers.Add("Translate:f");.

Les dejo un link referente a este ultimo tema. Parámetros con los que puede trabajar InfoPath Forms.

http://msdn.microsoft.com/en-us/library/ie/ms772417.aspx

Segundo paso importante:

Luego de obtener el Stream para el adjunto, se crea el Attachment del email, estableciendo para su ContentType correspondiente. Ejemplo:

   1: Attachment form = new Attachment(msForm, new ContentType("application/x-microsoft-InfoPathForm")); 

Tercer paso importante:

Agregar los siguientes headers al Mensaje:

   1: message.Headers.Add("Content-Class", "InfoPathForm.InfoPath");
   2: message.Headers.Add("Message-Class", "IPM.InfoPathForm.InfoPath");

 

Como expliqué en los párrafos anteriores, nuestra clase hereda de Activity. Esto implica que estamos obligados a implementar el método Execute sobrescribiéndolo con nuestra propia lógica. En el siguiente ejemplo podemos ver como quedaría nuestro código siguiendo las indicaciones anteriores:

   1: protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
   2: {
   3:     using (var web = __Context.Web)
   4:     {
   5:         try
   6:         {
   7:             // Obtiene la informacion necesaria para el mensaje que se envía, 
   8:             //relacionada al item actual sobre el cual esta corriendo el workflow. 
   9:             var message = BuildMailMessage(web);
  10:             
  11:             try
  12:             {
  13:                 using (SPSite site = new SPSite(AttachmentFileName))
  14:                 {
  15:                     using (SPWeb fileWeb = site.OpenWeb())
  16:                     {
  17:                         string nameForm;
  18:  
  19:                         //Stream del Archivo InfoPath xml
  20:                         Stream msForm = CreateResponseStream(fileWeb, AttachmentFileName, out nameForm);
  21:                         
  22:                         Attachment form = new Attachment(msForm, new ContentType("application/x-microsoft-InfoPathForm"));
  23:  
  24:                         message.Headers.Add("Content-Class", "InfoPathForm.InfoPath");
  25:                         message.Headers.Add("Message-Class", "IPM.InfoPathForm.InfoPath");
  26:  
  27:                         message.Attachments.Add(form);
  28:                     
  29:                     }
  30:                 }
  31:  
  32:             }
  33:             catch (Exception ex)
  34:             {
  35:                 // NO se pudo encontrar e archivo.
  36:                 Common.WriteFailToHistoryLog(web, WorkflowInstanceId, string.Format(CultureInfo.InvariantCulture, "No se pudo adjuntar el archivo: '{0}' - Mensaje: {1}.", AttachmentFileName, ex.Message));
  37:             }
  38:  
  39:             if (!string.IsNullOrEmpty(From))
  40:             {
  41:                 //Se obtiene la cuenta del usuario enviador del mail
  42:                 message.From = GetMailAddress(__Context.Web, From);
  43:                 Common.WriteFailToHistoryLog(web, WorkflowInstanceId, string.Format(CultureInfo.InvariantCulture, "From: {0}", message.From));
  44:             }
  45:  
  46:             if (message.To.Count > 0)
  47:             {
  48:                 // Se establece el objeto SMTP en base a la configuracion del smtp de nuestro Sharepoint
  49:                 SmtpClient smtpClient = LoadSmtpInformation();
  50:  
  51:                 if (message != null)
  52:                     Common.WriteFailToHistoryLog(web, WorkflowInstanceId, string.Format(CultureInfo.InvariantCulture, "Direccion de mail del From: {0} - To: {1} -  ", message.From.Address, message.To[0].Address));
  53:                 smtpClient.Send(message);
  54:  
  55:                 // Log en el historial del Workflow
  56:                 Common.WriteSuccessToHistoryLog(web, WorkflowInstanceId, string.Format(CultureInfo.InvariantCulture, "Email correctamente enviado a los usuarios: {0}", message.To));
  57:             }
  58:             else
  59:             {
  60:                 // Log en el historial del Workflow
  61:                 StringBuilder emailAddressesTo = new StringBuilder();
  62:                 for (int i = 0; i < To.Count; i++)
  63:                 {
  64:                     emailAddressesTo.AppendFormat(CultureInfo.InvariantCulture, "{0}, ", To[i]);
  65:                 }
  66:                 // Trim de la utlima coma
  67:                 emailAddressesTo = emailAddressesTo.Remove(emailAddressesTo.Length - 1, 2);
  68:  
  69:  
  70:                 Common.WriteFailToHistoryLog(web, WorkflowInstanceId, string.Format(CultureInfo.InvariantCulture, "Unable to send email out. No valid user email addresses for the following users ({0}) were found.", emailAddressesTo));
  71:             }
  72:         }
  73:         catch (Exception ex)
  74:         {
  75:             // Log en el historial del Workflow
  76:             Common.WriteFailToHistoryLog(web, WorkflowInstanceId, string.Format(CultureInfo.InvariantCulture, "Falló el envío de mail. Mensaje de Error: {0}", ex.Message));
  77:         }
  78:         finally
  79:         {
  80:             // Cleanup - Dispose de las propiedades privadas antes de salir
  81:             if (__ActivationProperties != null)
  82:             {
  83:                 __ActivationProperties.Dispose();
  84:             }
  85:  
  86:             if (__Context != null)
  87:             {
  88:                 __Context.Dispose();
  89:             }
  90:         }
  91:     }
  92:  
  93:     return ActivityExecutionStatus.Closed;
  94: }
  95:  
  96: private Stream CreateResponseStream(SPWeb fileWeb, string nameFile, out string name)
  97: {
  98:     SPFile attachment = null;
  99:     attachment = fileWeb.GetFile(nameFile);
 100:     name = attachment.Name;
 101:     WebRequest req = WebRequest.Create(nameFile);
 102:     req.Headers.Add("Translate:f");
 103:     req.Credentials = CredentialCache.DefaultNetworkCredentials;
 104:     WebResponse response = req.GetResponse();
 105:     Stream msForm = response.GetResponseStream();
 106:  
 107:     return msForm;
 108: }
 109:  
 110: private static SmtpClient LoadSmtpInformation()
 111: {
 112:   string smtpServer = SPAdministrationWebApplication.Local.OutboundMailServiceInstance.Server.Address;
 113: return new SmtpClient(smtpServer);
 114: }

Veamos un poco el código. Primero obtenemos el Contexto Web actual. Luego usando  algunos métodos helpers construimos el mensaje (BuildMailMessage)

Después de crear el mensaje tratamos de cargar el adjunto especificado por la propiedad. Para esto usamos la propiedad AttachmentFileName para abrir el SPSite donde el archivo reside. Luego abrimos un SPWeb para obtener el archivo en cuestión. (dentro del método CreateResponseStream).

Desarrollamos los tres pasos definidos en los párrafos anteriores. Y finalmente establecemos el SMTP de nuestro Sharepoint (LoadSmtpInformation ) y con el método GetMailAddress obtenemos las direcciones de correo en caso de que en los parámetros nos llegue el Account Name.

4 - Registración de Custom Action.

Antes de usar nuestra Custom Action debemos, primero, registrarla en el Web.config de nuestro Sharepoint. Para hacer esto usaremos un Feature Reciver que ejecute esta acción durante la activación.

Como agregar un EventReciver:

 

image

 

Esto nos generará una clase Vemn.EventReceiver.cs en la cual vamos a implementar los siguientes métodos:

   1: public override void FeatureActivated(SPFeatureReceiverProperties properties)
   2: {
   3:     SPWebApplication webapp = (SPWebApplication)properties.Feature.Parent;
   4:     UpdateWebConfig(webapp, true);
   5:  
   6: }
   7:  
   8: public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
   9: {
  10:     SPWebApplication webapp = (SPWebApplication)properties.Feature.Parent;
  11:     UpdateWebConfig(webapp, false);
  12:  
  13: }
  14:  
  15: private void UpdateWebConfig(SPWebApplication webApp, bool featureActivated)
  16: {
  17:     SPWebConfigModification modification =
  18:        new SPWebConfigModification("authorizedType[@Assembly=\"Vemn.CustomActivity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7819e4834cee4b0e\"][@Namespace=\"Vemn.CustomActivity\"][@TypeName=\"*\"][@Authorized=\"True\"]", "configuration/System.Workflow.ComponentModel.WorkflowCompiler/authorizedTypes");
  19:  
  20:     modification.Owner = "Vemn.CustomActivity";
  21:     modification.Sequence = 0;
  22:     modification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
  23:     modification.Value =
  24:          string.Format(CultureInfo.InstalledUICulture,
  25:          "<authorizedType Assembly=\"{0}\" Namespace=\"{1}\" TypeName=\"{2}\" Authorized=\"{3}\"/>",
  26:          new object[] { "Vemn.CustomActivity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7819e4834cee4b0e", "Vemn.CustomActivity", "*", "True" });
  27:  
  28:     if (featureActivated)
  29:         webApp.WebConfigModifications.Add(modification);
  30:     else
  31:         webApp.WebConfigModifications.Remove(modification);
  32:  
  33:  
  34:     SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
  35: }

Esto agregará o removerá un nodo authorizedType en el Web.config de nuestro Sharepoint, para habilitar el uso de nuestra Action en el Workflow Designer.

Agregar una entrada Safecontrol en el manifiesto de nuestro Package.

Para asegurarnos de que Sharepoint Cargue de manera segura nuestra CustomAction es que añadimos la entrada SafeControl sobrescribiendo el archivo Package.Template.xml de la siguiente manera:

   1: <Assemblies>
   2:     <Assembly Location="Vemn.CustomActivity.dll" DeploymentTarget="GlobalAssemblyCache">
   3:         <SafeControls>
   4:             <SafeControl Assembly="$SharePoint.Project.AssemblyFullName$" Namespace="$SharePoint.Project.FileNameWithoutExtension$" TypeName="*" />
   5:         </SafeControls>
   6:     </Assembly>
   7: </Assemblies>

Ahora si ya estamos en condiciones de compilar, hacer el deploy y testear.

Creamos un Workflow Reusable y revisamos si nuestra Custom Acrivity está disponible para usar.

image

Deberíamos poder seleccionarla e insertarla como sentencia.

image

Conclusión

Como pudimos ver, Sharepoint 2010 nos permite extender las capacidades de la versión OOB. Esto sumado a los Workflows Reusables nos dan una gran flexibilidad para el diseño y desarrollo de soluciones que exigen considerados niveles de personalización.

Tags: , , , ,

.NET | Sharepoint | Visual Studio

Consultorio de SharePoint - Evento a distancia

por Alejandra Federico  1. febrero 2012

El jueves 2 de febrero Daniel Laco brindará una charla virtual sobre el Branding en SharePoint.

Se llevará a cabo a las 15:00 hs., la apertura de la sala virtual es a partir de las 14:45.

Los esperamos para compartir durante una hora las experiencias en el uso de SharePoint. 


Evento gratuito. 

Para más información e inscripción AQUÍ

Tags:

Sharepoint

Evento Sharing the Point – Buenos Aires – 21/Enero

por Daniel Laco  20. enero 2012

Después de su gran éxito en el 2011 en Asia y Europa, continua la gira mundial de Sharing The Point. En esta ocasión un grupo de evangelistas y expertos de SharePoint de múltiples nacionalidades estarán brindando un conjunto de charlas en Buenos Aires, para arrojar luz sobre el potencial ilimitado de SharePoint para las Organizaciones de todo tamaño y sector.

No te pierdas el nutrido grupo de expertos que participarán del evento: Joel Oleson (USA). Paul Swider (USA), Mark Miller (USA), Dan Holme (Hawaii), Ricardo Muñoz (Costa Rica), Fabián Imaz (Uruguay), Fernando Hunth (Argentina), Mauricio Grimberg (Argentina) y Ariel García Sobrino (Argentina). Ellos estarán compartiendo experiencias, mejores prácticas y lecciones aprendidas durante una gran cantidad de implementaciones de SharePoint de diversos tipos y tamaños realizadas en múltiples países.

Si queres aprender más sobre SharePoint, y al mismo tiempo aprovechar la experiencia de los expertos, te invitamos a reservar tu lugar en el evento que se realizará el sábado 21 en las oficinas de Microsoft Argentina (Bouchard 710 4° – CABA). Visita hoy mismo el Sitio Oficial de la Gira “Sharing The Point Sudamérica”.

El evento será totalmente gratuito. Lo único que necesitas hacer es registrarte haciendo clic aquí.

Los esperamos para compartir el desayuno por la mañana, un almuerzo al mediodía, y un cierre en el que se obsequiarán varios regalos.

Agenda

Horario

Track 1 (Sala Roble)

Track 2 (Sala Ombú)

8:45 – 9:30

Acreditación / Recepción de asistentes / Desayuno

9:30 – 9:45

Bienvenida al evento / Presentación de Sponsors

9:45 -10:45

Social Intranets: Transforming Traditional Portals

  • Audiencia: End User / IT Pro/ Developer/Business
  • Speaker.: Joel Oleson
  • Idioma: Ingles, con traducción

Building the Perfect SharePoint 2010 Farm: Real World Best Practices from the Field

  • Audiencia: IT Pro
  • Speaker.: Michael Noel
  • Idioma: Ingles, con traducción

 

10:45 – 10:55

Break (Café)

10:55 – 11.55

To Host or Not to Host: The Good, the Bad and the Ugly Decisions

  • Audiencia: Business / IT Pro
  • Speaker.: Mark Miller
  • Idioma: Ingles, con traducción

 

Architecting SharePoint for Scalability and Enforceable Governance

  • Audiencia: IT Pro, Information Architects, Governance Body
  • Speaker.: Dan Holme
  • Ingles, con traducción

 

11:55 – 12:35

Almuerzo

12:35 – 12:50

Presentación de Sponsors

12:50 – 13:50

Developing and Extending Enterprise Content Management Features

  • Audiencia: IT Pro, Developer
  • Speaker.: Paul Swider
  • Idioma: Ingles, con traducción

 

Branding SharePoint

  • Audiencia: Developer
  • Fernando Hunth
  • Idioma: Español

13:50 – 14:00

Break (Café)

14:00 – 15:00

SharePoint XXX (Sólo para adultos): El qué y el cómo de una mejora dramática de procesos

  • Audiencia: End User / IT Pro/ Developer/Business
  • Speakers: Mauricio Grimberg, Ariel García Sobrino
  • Idioma: Español

 

Migrate to SharePoint 2010… and live to tell the story.

  • Audiencia: It Pro
  • Speakers: Ricardo Munoz, Fabián Imaz
  • Idioma: Español

15:00 – 15:15

Cierre del evento / Agradecimientos / Regalos

Sponsors del evento

image
Perception Aycron
baufest Vemn
Latinshare

 

La gira sigue por las siguientes ciudades de Sudámerica:

  • Enero 23, 2012 - Montevideo, Uruguay
  • Enero 24, 2012 - Santiago, Chile
  • Enero 26, 2012 - Ciudad de las Estrellas, Antártida

Los esperamos!

Tags:

Sharepoint

Enlazar dos combos en Cascada en Microsoft InfoPath con listas de SharePoint

por Franco Beperet  29. noviembre 2011

Uno de los temas más comunes a la hora de configurar un formulario digital es el de establecer una dependencia entre dos (o más) combos, es decir, que en base a lo seleccionado en el primer combo se filtren los datos que le corresponde a la opción seleccionada del primer combo en el segundo combo.

Un ejemplo común, y seguramente ya utilizado en algún formulario de la Web, es el de tener dos combos, uno con ‘Provincias’ y otro de ‘Ciudades’ que se basa a lo seleccionado en ‘Provincias’, a su el combo ‘Provincias’ puede depender de un combo padre que sea ‘Países’ y el combo de ‘Ciudades’ tener un combo hijo llamado ‘Barrio’.

En nuestro ejemplo para Microsoft InfoPath trabajaremos con los combos ‘Provincias’ y ‘Ciudades’…

- Configuración Lado SharePoint

Empecemos, lo primero que tendríamos que configurar son las listas en nuestro sitio SharePoint. Primero creamos la lista de ‘Provincias’ (hay que respetar el orden de creación, después se vera porque motivo) configurándola para que al cargarle datos quede de la siguiente manera:

ListaProvincias

Luego crearemos la lista de ‘Ciudades’ a la cual le crearemos dos columnas una de ‘Ciudad’ y otra de ‘Provincia’ con la siguiente configuración:

ConfiguracionListaCiudad

Acá se ve que el motivo de crear primero la lista ‘Provincias’ es porque en la columna ‘Provincia’ de la lista ‘Ciudades’ hay que hacer una referencia a la respectiva columna de la primer lista.

Una vez finalizada la configuración, hay que cargarle los datos para que nos termine quedando la lista de la siguiente forma:

ListaCiudades

Teniendo esto finalizado, ya tenemos nuestra configuración del lado SharePoint finalizado, solo nos queda configurar el lado InfoPath…

- Configuración Lado InfoPath

En el formulario tenemos que crear las conexiones que reciben datos de las listas de nuestro sitio, para ello:

  1. Abrimos nuestro formulario InfoPath.
  2. Vamos a Datos –> Obtener datos externos –> Desde la Lista de SharePoint.
  3. Insertamos la URL de nuestro sitio y luego elegimos la lista ‘Provincias’.
  4. Tildamos las siguientes opciones:RecibirListaProvincia
  5. Tildamos ‘Recuperar datos automáticamente cuando se abre un formulario’ y finalizamos.
  6. Repetimos el punto 3 y punto 4 pero seleccionando la lista ‘Ciudades’.
  7. Tildamos las siguientes opciones:RecibirListaCiudad
  8. Tildamos ‘Recuperar datos automáticamente cuando se abre un formulario’ y finalizamos.

 

Ya tenemos nuestras dos conexiones configuradas. El paso siguiente a las conexiones es configurar los combos…

  1. En las propiedades del combo correspondiente a ‘Provincias’ tildamos sobre ‘Obtener datos de un origen de datos externo’.
  2. Configuramos de la siguiente manera:PropiedadesComboProvincias
  3. Repetimos el Paso 1 pero lo dejamos configurado de la siguiente manera:PropiedadesComboCiudades

 

Ahora hacemos click derecho en el combo de ‘Provincias’ y seleccionamos ‘Reglas’ –> ‘Administrar reglas’ y configuramos la siguiente regla…

  1. Creamos nueva regla del tipo Acción y le colocamos un nombre.
  2. La condición tiene que ser cuando el combo no está en blanco.
  3. Agregamos una acción que sea ‘Establecer el valor de un campo’.
  4. La configuración de esta acción tiene que ser:

- Campo es igual a: ValorCampoRegla- Valor es igual a:ValorRegla

Después agregamos otra acción a la misma regla que sea ‘Realizar consulta usando una conexión de datos’ que tenga como conexión de datos la de ‘Ciudades’ (depende el nombre que se la halla puesto cuando se creo la conexión).

La regla debe quedar de la siguiente forma:

Regla

Hacer una vista previa y comprobar que se va filtrando el combo de ‘Ciudades’ en base a lo seleccionado en el combo de ‘Provincias’.

Tags: ,

Sharepoint

Sharepoint 2010 - El modelo de licenciamiento

por Daniel Laco  17. mayo 2011

Tags:

Sharepoint

Historia de la productividad o como impacta Sharepoint y otras herramientas

por Daniel Laco  10. mayo 2011

Muy buen video de Microsoft, sobre la productividad. Vemos la plataforma Sharepoint, Lync y Office trabajar integradamente. Suena interesante.

Tags:

Sharepoint

Configuring co-authoring in SharePoint 2010

por Daniel Laco  29. marzo 2011

Investigando sobre el mundo SharePoint me encontré con una guía para que los administradores configuren la co – autoría de su organización.
En ella explican cómo configurar las versiones, el período de creación de las mismas, el número máximo de autores y la posibilidad de deshabilitar la co- autoría.
A continuación les dejo un breve resumen y los links correspondientes, donde encontrarán detalladamente la configuración de cada uno de los puntos expuestos a continuación.

-Los autores pueden trabajar el mismo documento, y las ediciones se almacenarán en el servidor como versiones de documentos.
-Si se activa la versión, SharePoint Server toma instantáneas periódicas de los documentos, y los guarda para futuras consultas.
-Los administradores pueden limitar el número máximo de autores que pueden ser co-autores de un documento al mismo tiempo.
-Los co-autores también pueden ser deshabilitados por el cliente, utilizando la directiva del grupo.

Configure versioning for co-authoring
Configure the co-authoring versioning period
Configure the maximum number of co-authoring authors
Disable co-authoring

Tags: , ,

Sharepoint | TFS

Nueva area de recursos sobre ALM y SharePoint

por Daniel Laco  4. febrero 2009

Una nueva area en el sitio de MS sobre Sharepoint y ALM.

Se acaba de publicar el Application Lifecycle Management Resource Center for SharePoint Server

Aqui se pueden encontrar guias, articulos, links, herramientas sobre todo lo relacionado con ALM y Sharepoint.

Hay temas como:

  • Templates para Visual Studio
  • Control de código fuente.
  • Testing
  • Builds
  • TFS
  • Etc. etc. etc.

 

Sharepoint-ALM

 

Tags: ,

ALM | Gestión de Proyectos | Metodologías y Procesos | Sharepoint

Desarrollando WebParts de Sharepoint y AddIn de Outlook para Team Foundation Server

por Ariel  21. octubre 2008

Desarrollando WebParts de Sharepoint y AddIn de Outlook para Team Foundation Server

Estamos desarrollando unos componentes que permitan hacer seguimientos de Workitems tanto desde Sharepoint como desde Outlook.

Estos componenets apuntan a otros tipos de stakeholders que no son desarrolladores, pero que necesitan poder hacer un seguimiento de un proyecto. En general son Gerentes de Sistemas, Project Leaders, etc. que no tienen instalado Visual Studio, pero si otro tipo de herramientas.

En el caso de Sharepoint estamos desarrollando unos webparts que casi todo el funcionamiento del Team Explorer, sin la parte de control de versiones.

Ahora podemos recorrer los proyectos, editar WorkItems y hacer consultas desde de un portal de Sharepoint.  Esto es posible porque se puede componer una pagina con varios WebParts conectados entre si.

En Outlook el AddIn cuenta con la misma funcionalidad.

A continuación mostramos algunas imagenes de la beta de estos componentes:

Webparts en esquema de una columna


Por último se puede ver un formulario similar al del Team Explorer en donde se ven todos los detalles de un Workitem.

Webparts en esquema de dos columnas

En la imagen abajo se puede ver la utilización de un arbol fijo en donde se pueden ver las consultas de cada proyecto. Y otro webpart en donde se cargan los Workitems de una consulta.

Plugin para Outlook

Tags: ,

Sharepoint | Visual Studio

Acerca de los Autores

Este es el blog del equipo de VEMN SA 
Presentaremos temas que nos parezcan de interés sobre tecnología .NET, Procesos y Metodologías y todo aquello relacionado con el proceso de desarrollo de Software

Month List

BlogRoll

Download OPML file OPML