Estrategias de Desarrollo en Sharepoint

por Daniel Laco  3. octubre 2014

 

Presentación del evento que realizado en el MUG sobre Desarrollo en Sharepoint el 2 de Octubre de 2014.

 

Tags:

Eventos | Sharepoint

VEMN es nombrado Partner Gold de Microsoft en Sharepoint

por Alejandra Federico  22. enero 2013

La empresa alcanzó la máxima distinción en la categoría Collaboration and Content (Sharepoint), consolidándose en el sector como una de las pocas empresas que están certificadas en dicha categoría.

Con más de 20 años en el mercado Vemn alcanzó el máximo reconocimiento entre sus pares. 

Con esta certificación, la empresa cuenta con el apoyo de Microsoft teniéndola en cuenta dentro del grupo de partners preferidos para proyectos y servicios basados en Sharepoint.

Vemn tuvo que cumplir una serie de requisitos, entre los cuales se destaca la certificación de varios profesionales en relación a las tecnologías de Sharepoint, luego de pasar por diversos exámenes, y una cierta cantidad de referencias de sus clientes actuales.

“Estamos muy contentos de ser Partner Gold de Microsoft, nuestros clientes podrán acceder a la implementación de soluciones Microsoft, apoyados por un equipo de profesionales altamente calificados. Con Microsoft tenemos una excelente relación que nos interesa profundizar y sabemos que esta es una forma de acercarnos aún más. Seguimos demostrando el esfuerzo para entregar el mejor servicio.”

Patricia Scalzone, Presidente de Vemn Sistemas.

Tags:

Sharepoint

Sharepoint 2013 - Que hay de nuevo? - Charla en el MUG

por Alejandra Federico  8. enero 2013

El Jueves 7 de Febrero realizaremos una jornada en el MUG sobre:

SHAREPOINT 2013

Orador: Daniel Laco

Resumen: Esta presentación está centrada en mostrar las nuevas características que tiene la plataforma Sharepoint 2013.

a) Nuevas capacidades de usabilidad, 

b) Cambios de arquitectura en IT y 

c) nuevas concepciones para el desarrollo de aplicaciones.

Datos del Evento:

Jueves, 7 de Febrero del 2013 de 09:30 a 11:30 hs.

en el Auditorio del MUG, Rivadavia 1479, Piso 1°A, Capital Federal.

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

 

Presentación de la conferencia (PPTs)

Tags:

Sharepoint

Automatizando Procesos de Negocios en Sharepoint con Workflows e InfoPath

por Alejandra Federico  21. agosto 2012

El martes 18 de Septiembre realizaremos un workshop en el MUG:

"Automatizando Procesos de Negocios en Sharepoint con Workflows e InfoPath"

Oradores: Daniel Laco, Mauricio Rodríguez, Franco Beperet 

Horario: 18 a 22 hs 

Resumen: 
Uno de los pilares de la plataforma Sharepoint es la facilidad de creación de formularios y workflows.

Estas características permiten en las organizaciones automatizar una amplia variedad de circuitos, reemplazando planillas y documentos existentes.

En este workshop se realizará una introducción  al armado de Workflows y Formularios. 

Apoyados en herramientas como Sharepoint Designer e InfoPath se mostrarán ejemplos de casos reales. 

Temario:

• 
Qué cosas resuelvo con InfoPath y Workflows
 

• Workflows:

Una introducción.

o Workflows en la caja (de Aprobación, de Recolección de Firmas, de Publicación)

o Creando un flujo desde cero con Sharepoint Designer

o Personalizando Tasks

o Custom Activities para el Designer
 

• InfoPath

o Conceptos Generales

o Vistas

 Personalización en función del Usuario

 Integración con páginas del sitiio 

o Validando datos

o Formateo de datos

o Conectando con Datos Externos

 

Datos del Evento:

Martes, 18 de Septiembre del 2012.

en el Auditorio del MUG, Rivadavia 1479, Piso 1°A, Capital Federal.

Más info
AQUI 

 

 

 

Tags:

Sharepoint

Sharepoint Summit en el MUG - 23 de Mayo

por Alejandra Federico  24. abril 2012

El miércoles 23 de Mayo se realizará en el auditorio del MUG de 14 a 19 hs. una jornada dedicada integramente a Sharepoint, donde se presentarán las siguientes temáticas:

Temario:

14:00 – 14:15

 Presentación del evento Daniel Laco (Vemn Sistemas)

 

 


14:15 – 15:00

 Enterprise Search: Alternativa a la libreta de direcciones. 
 Daniel Laco – Mauricio Rodríguez (Vemn Sistemas)

 Con Enterprise Search se expanden notablemente las capacidades de búsqueda de personas en la   empresa y la posibilidad de vincular de manera mas efectiva a quienes tienen el conocimiento con quienes lo necesitan.
Se presentará un caso donde se integrará información de usuario desde aplicaciones externas (Ej: PeopleSoft, Meta4, AD, etc.) y como esta capacidad redunda en beneficios para la mejora de la interrelación de las personas en la empresa.

15:00 – 15:15

 Break

 

 

15:15 – 16:00

 Alta Disponibilidad de SQL Server Maxi Acotto (Conduit) 
 
 Armar un esquema de alta disponbilidad en Sharepoint, requiere de atacar diferentes aristas de la plataforma (IIS, SQL Server, NLB, etc.)
Uno de los componentes fundamentales en la performance y disponiblidad es SQL Server.
En esta presentación se explicará el camino para implementar de estas características con SQL Server.

 

16:00 – 16:45

 ¿Qué significa Gobernabilidad? Cómo aplicarla a SharePoint.
 Ariel García Sobrino (Microsoft)

 Definición de roles, responsabilidades y políticas que soporten el crecimiento y evolución de la plataforma

16:45 – 17:00

 Break

 

 

17:00 – 17:45

 Automatización de procesos de negocio Alan Scheinkman (Perception Group)

 Durante la demostración, se vera como a través de herramientas estándar de Sharepoint y sin necesidad de programación, tenemos la posibilidad con Sharepoint de automatizar procesos de negocios utilizando nuestros propios formularios y flujos de trabajo.

 

 

17:45 – 18:30

 Caso de Éxito: Implementación de Sharepoint 2010 como intranet corporativa en Telefónica. Alexis Torchinsky (Telefónica)

 El líder técnico y responsable de la implementación contará de primera mano la experiencia de la puesta en marcha de esta solución.
Explicará la estrategia utilizada, los aciertos, las dificultadas encontradas y también los temas importantes que dejó la experiencia y fueron fundamentales para el éxito de la implementación.

18:30 – 18:45

 Cierre del Evento y Sorteos Oscar Turquet (MUG)

 

Datos del Evento:

Miércoles, 23 de Mayo del 2012

de 14:00 a 19:00 hs.

Auditorio del MUG
Rivadavia 1479, Piso 1°A, Capital Federal

Más información e inscripción
AQUÍ

Tags:

Eventos | Sharepoint

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

Extensible Connectivity Management Agents (ECMA) para Forefront Identity Manager (FIM) - I

por Mauricio Rodriguez  23. diciembre 2011

Forefront_IdentityManager_2010_rgb_180x51_nEGRO

Creo que es apropiado encarar este post desde una de las grandes problemáticas que se esta empezando a dar en la actualidad:

En la medida en que los sistemas de las organizaciones se van multiplicando con el paso del tiempo, la administración de identidades (información de usuarios) entre dichos sistemas se va complejizando volviéndose un trabajo arduo, tedioso y en muchos casos incontrolable. Es importante tener en cuenta los riesgos de seguridad que pueden tener lugar en escenarios de este tipo. Para ilustrar un poco esto, les daré un ejemplo real en unas de las empresas en la cual trabajé:

”La organización contaba con una gran variedad de sistemas y tecnologías como Microsoft Sharepoint, SAP, Oracle, Biztalk, etc. Nos informan que un directivo de alto rango había sido despedido, por lo que tenía que empezar un proceso de baja de usuario en todos los sistemas en los que estaba registrado, con todo lo que esto significa, ya que había varias instancias de este usuario en cada  una de las aplicaciones en las que había tenido actividad. Lo interesante de esta anécdota es que el informe lo recibimos a los últimos minutos de finalizar la jornada laboral un día Viernes, por lo que tuvimos que poner leña al fuego y tratar de ubicar a todos los responsables de cada departamento para pedir la baja de este usuario, si es que aún no se habían retirado. Recuerdo que fue un día largo y nos trajo muchos dolores de cabeza.”

Forefront Identity Manager (FIM) es una plataforma de administración de identidades, credenciales y políticas de acceso de Microsoft, destinada a cubrir este tipo de dificultades.

Voy a desarrollar brevemente y lo más claro posible, qué es Forefront Identity Manager para los que no lo conocen. Y como final y puntapié inicial del próximo post, introducirnos a los Management Agents de FIM.

Introducción

Para comenzar, vamos a ver dos imágenes interesantes. La primera es bastante intuitiva y nos va a servir para armar un mapa mental sobre el concepto de FIM:

 

image

Como pueden ver Forefront Identity Manager 2010, posee la capacidad de integrar identidades de diferentes aplicaciones y datasources, centralizando y sincronizando información. A partir de este sistema centralizado, los administradores pueden definir políticas, manejar credenciales, usuarios y grupos de modo que estos cambios puedan impactar en las aplicaciones o data sources conectados a FIM. Una de las cosas más importantes que nos provee FIM es la posibilidad de personalizar los conectores, pudiendo estos, ser desarrollados en Visual Studio, lo que implica que podamos hacer extensible el manejo y sincronización de los datos hacia cualquier sistema que disponga de una interfaz de comunicación.

En FIM 2010 Disponemos de un Portal basado en Sharepoint y la consola de Sincronización, desde donde es posible visualizar y administrar todas estas operaciones, como las Reglas de Sincronización, Workflows, Mapeos, etc.

Una vez conceptualizado esto, podemos pasar a la siguiente imagen para observar un poco mas en detalle los componentes de la arquitectura de FIM:

image

 

Para el tema en desarrollo nos vamos a concentrar en los siguientes componentes principales: el Portal (2), los Adapters (10), estos serán nuestros Management Agents (MA), el FIMSync (11), el cual es el corazón de esta plataforma que como pueden ver es el encargado de integrar a los Identity Stores y por último el FIM Service que involucra los componentes 5,6,7 y 8.

Para mas información sobre los demás componentes, les dejo el link de msdn http://msdn.microsoft.com/en-us/library/windows/desktop/ff182370.aspx

Como trabajan estos?

Como mencioné antes, FIM dispone de la capacidad de conectar múltiples Identity Stores o DataSources por medio de los MAs. Cada MA que se crea para alguna conexión, dispone de una base de datos propia llamada ConnectorSpace (esta base es creada por FIM cada vez que se crea un MA).

Supongamos que una de las aplicaciones conectadas a FIM realiza alguna modificación en los datos de un usuario, como podría ser la dirección de mail, el teléfono o el lugar de trabajo. El MA de este sistema importará los datos modificados al ConnectorSpace. Luego se ejecuta una sincronización que creará, o actualizara en caso de que existan, estos datos en una base única llamada Metaverse, luego, mediante, una Regla de Sincronización (Synchronization Rule), se detectan que DataSources utilizan estos datos de modo de importarlos a los ConnectorSpaces correspondientes, para finalmente ser exportados a dichos DataSources.  De este modo se mantiene la consistencia de datos referente a usuarios o grupos en todos los sistemas que estén conectados y vinculados mediante las Reglas de Sincronización.

 

 

MVAndCS

Les dejo la documentación en donde puede ver con mayor detalle todos los aspectos de la sincronización:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms698364.aspx

Para nuestro objetivo nos vamos a enfocar sobre los MAs (Management Agents). Los MA son componentes (dlls), desarrollados en Visual Studio .Net, que residen en el servidor de Sincronización, encargados de realizar las operaciones de importación y exportación de los datos.

image

 

Es claro en la imagen, la interfaz que brindan estos MA para la integración de aplicaciones.

En FIM disponemos de una basta lista de MA para crear y configurar, como por ejemplo para integrar SQL, AD, SAP, etc. Pero que pasa si ninguno de estos cumple con los requerimientos del cliente?,  o si nuestro MA tiene que realizar algún proceso en particular?, y aquí ya nos vamos perfilando al tema troncal de este post, tenemos la posibilidad de desarrollar nuestros propios Extensible Connectivity Management Agent (ECMA) a partir una API (Microsoft.MetadirectoryServices.dll) que nos provee FIMSynchronizationService.

En el próximo post estaremos viendo como desarrollar e implementar un Management Agent personalizado para integrar un sistema de  facturación a través de sus WebServices.

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

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