Workflow de Nintex con llamada a Web Service

Ya vimos en otro post anterior cómo utilizar Nintex para crear un flujo de trabajo sencillo. En este otro ejemplo vamos a crear un flujo sencillo que se conecte a un Web Service para trabajar con su respuesta.

El ejemplo va a ser crear una lista donde guardar una dirección de email, y lanzar el flujo sobre ese elemento para hacer una llamada a un servicio y que nos indique si el email es válido o no.

La dirección del servicio que voy a usar es la siguiente: http://ws.cdyne.com/emailverify/Emailvernotestemail.asmx?wsdl

Lo primero es construir la lista que vamos a usar para guardar los emails. En este caso vamos a usar el campo Title para guardar la dirección, y un campo multilinea de texto plano para guardar la respuesta del servicio (luego veremos cómo tratar la respuesta). Algo así por ejemplo:

image

Sobre la lista creada vamos a crear un flujo de trabajo con Nintex.

image

Y vamos a insertar en primer lugar un componente de tipo Call web service:

image

Y lo configuramos. Lo primero es introducir la dirección URL del servicio al que vamos a atacar, y posteriormente, hacemos clic sobre el botón de Refresh para comprobar la llamada y para que nos descubra el WSDL y seleccionemos el método del servicio al que queremos llamar, en este caso VerifyEmail:

image

Lo siguiente es configurar la salida. Para ello primero vamos a crear una variable, donde guardaremos ese valor. En esta misma ventana, en la zona superior podemos acceder a las variables y crear una:

image

Para guardar la respuesta creamos una variable de tipo multilinea.

image

Y una vez creada la variable, terminamos de configurar la salida del servicio. (Antes hemos indicado en los parámetros del método al que vamos a llamar que el campo email vendrá de la variable Title que leemos de la lista en cuestión.) En este caso como queremos guardarlo en una variable plana para ver qué tipo de salida nos da, lo dejamos por ejemplo como sigue:

image

Y metemos un componente más en el flujo para guardar el valor de la salida del servicio en nuestro campo de la lista (usamos el componente Set field value):

image

Y lo configuramos de la siguiente manera, con el fin de que la variable que recoge el resultado del servicio se guarde en la columna de la lista que hemos llamado WSResult (hacemos uso del icono de la derecha para acceder a los tokens disponibles del workflow):

image

Y por último configuramos el flujo para indicar que queremos un arranque manual y con opción desde su menú contextual:

image

Y ya sólo faltaría probarlo. Creamos un par de elementos, uno con email válido y otro inválido y lanzamos el flujo para ver qué resultado obtenemos. Algo así:

image

image

Como vemos, el XML de la respuesta tiene una etiqueta con nombre GoodEmail que indica el resultado final, verdadero o falso. Vamos a modificar la lista para guardar ese valor en lugar de guardar el XML entero.

Para ello, creamos un campo nuevo en la lista de tipo booleano:

image

Y modificamos el componente de Call web service de nuestro flujo, en concreto el output, en donde ahora vamos a cambiar y donde pone Default value, vamos a seleccionar Specify elements, de forma que podemos navegar por el árbol de etiquetas del XML de la respuesta para seleccionar el deseado:

image

Y lo dejamos configurado de esta forma:

image

Y ahora, lo que vamos a hacer es incorporar al flujo un poco de lógica, de modo que si la respuesta que obtenemos en un texto que indica true, vamos a grabar el valor True en la columna de la lista y viceversa. Añadimos los siguientes componentes:

image

Y en el Run if, vamos a configurar lo que hemos descrito:

image

Si la acción continúa en el If, vamos a establecer el valor de la columna con un True, así que añadimos el componente Set field value:

image

Y lo configuramos para que guarde un True, ya que siempre que entremos por esta rama del If es porque el valor es verdadero:

image

Ahora, para replicar esta rama a la del else, en vez de crear otra vez cada componente, podemos copiar y pegar la actual y cambiar las condiciones:

image

image

Cambiamos las condiciones de la rama nueva para que entre cuando el valor sea false, y a la vez en la columna se guarde un False también. El resultado es un flujo como el siguiente:

image

Y si ahora lanzamos de nuevo el flujo sobre los elementos que ya teníamos creados, vemos que el resultado es el que buscábamos (faltaría eliminar la columna antigua, ya que los valores que tenía no se eliminan solos):

image

Primeros pasos con Nintex Workflow en SharePoint 2013

Para el que no conozca Nintex Workflow, es una herramienta que permite diseñar y publicar flujos de trabajo dentro de SharePoint, sin necesidad de una herramienta externa como pueda ser Visual Studio o SharePoint Designer. Nintex cuenta con un gran número de componentes a través de los cuales podemos construir distintos tipos de flujos.

En este post vamos a ver cómo crear un flujo muy básico sobre una lista, omitiendo todo el proceso de instalación de la herramienta.

Lo primero de todo será activar las características necesarias dentro de nuestro portal, así como comprobar que la licencia es válida y la configuración de la base de datos de Nintex es correcta.

Vamos a crear un flujo que, cuando se cree un elemento en una lista, se produzca la creación de otro elemento en una lista “espejo”, usando además un par de trazas para poder monitorizar el resultado de la ejecución.

Vamos a crear en primer lugar una lista (NList), y vamos a crear un flujo de trabajo sobre ella, utilizando el Wizard de Nintex (Create a Workflow in Nintex Workflow):

image

Seleccionaremos una plantilla en blanco para construir nuestro flujo desde cero:

image

Podemos ver que nuestro área de trabajo se divide fundamentalmente en tres zonas, una superior (Ribbon) donde están las opciones de guardar, publicar y opciones del flujo entre otras, un panel izquierdo donde vamos a encontrar los componentes agrupados por categorías, y una zona central donde vamos a arrastrar esos componentes hasta formar nuestro flujo de trabajo:

image

Si echamos un vistazo a los ajustes generales del flujo, podremos acceder a opciones tales como establecer título y descripción al flujo, configurar el auto-start, configurar los criterios de arrancado, y otra serie de opciones:

image

Vamos a comenzar arrastrando un componente de tipo traza en el log para monitorizar el comienzo del flujo, seguido de otro componente que será el de crear el item en la lista “espejo” que hemos creado previamente:

image

Para configurar el componente de Create item, accedemos desde su menú contextual a las opciones de configuración, y podemos establecer algo como lo siguiente:

image

En donde hemos fijado la lista sobre la que vamos a trabajar, y el texto que queremos configurar en el campo Title de la misma, usando el campo Title de la lista origen, a través de un selector que nos permite coger ese tipo de propiedades.

Añadimos una traza al final y tenemos un flujo muy básico con el siguiente aspecto:

image

Lo publicamos y comprobamos que efectivamente nuestra lista NList tiene configurado el flujo que acabamos de crear:

image

Ahora podemos crear un elemento y ver si se crea su copia espejo. En este caso yo me he encontrado con dos problemas.

Por un lado, que no se puede realizar el auto-start de un flujo de trabajo si la cuenta que estamos usando para probar es la de System Account. Al ver que no se arrancaba de forma automática, he revisado las trazas y he visto el siguiente mensaje:

Declarative workflows cannot automatically start if the triggering action was performed by System Account. Canceling workflow auto-start. List Id: b7d9d101-f401-400a-bc6f-96ec0ada8df8, Item Id: 4, Workflow Association Id: 9fa0278e-6aeb-4632-97d6-95af76a379f8

Así que para probarlo, vamos a lanzarlo de manera manual. Una vez lanzado, veo que la ejecución ha fallado en el arranque del mismo. Reviso trazas de nuevo, y encuentro una excepción de este tipo:

RunWorkflow: Microsoft.SharePoint.SPException: <Error><CompilerError Line="0" Column="10" Text="The type or namespace name 'Nintex' could not be found …

Revisando la configuración, me doy cuenta de que he olvidado activar Nintex para la Web Application sobre la que estoy trabajando, así que lo activo (Web Application activation):

image

image

Vuelvo a probar, y ahora si ha funcionado. Compruebo que se ha creado su copia en la lista espejo:

imageimage

Y si ahora revisamos el histórico de ejecución del flujo de trabajo, podemos ver los mensajes de las dos trazas que habíamos configurado:

image

Búsquedas a través del modelo cliente de SharePoint 2013: KeywordQuery II

En el post anterior se mostraba cómo crear una query sencilla de búsqueda a través del modelo cliente. También vimos las propiedades que devolvía una búsqueda por defecto. Vamos ahora a ver cómo devolver más propiedades y a utilizar los filtros más básicos.

Incluir más propiedades en los resultados:

Ya vimos en el post anterior qué propiedades por defecto devolvía nuestra tabla de resultados de búsqueda. Ahora bien, si queremos incluir una propiedad que no lo esté, y que además existe en el almacén de metadatos de búsqueda, podemos agregar más propiedades a la query, de la siguiente forma:

image

De esta forma, cuando ejecutemos la consulta, podremos consultar el resultado y ver lo que nos devuelve:

image

La utilidad que tiene incluir propiedades en los resultados, es que nos permite, aparte de mostrarlas, realizar consultas y filtros usando dichas propiedades.

Filtrar resultados de forma básica con KeywordQuery:

Ahora por ejemplo, de los resultados anteriores, vamos a filtrar aquellos en los que el ContentType es de tipo Item. Para ello:

image

Y después de añadir el filtro, el resultado es el siguiente:

image

De esta forma, podemos filtrar para mostrar elementos con un cierto ContentTypeId por ejemplo, o una extensión de fichero concreta, etc. o incluso una columna personalizada.

Incluir una columna personalizada como Managed Property:

Para incluir dentro de los resultados nuestra propia columna personalizada, deberemos realizar una serie de pasos.

En primer lugar, crear la columna; en este caso, una columna de tipo boolean:

image

Y una vez añadida a nuestra lista, deberemos lanzar un Full Crawl, para que podamos mapearla a una managed property. Por lo tanto, crearemos después una managed property, y mapearemos a dicha columna:

image

image

Una vez creada, deberemos lanzar otro Full Crawl para que los valores de nuestra columna se propaguen a la managed property. Una vez realizado, podremos lanzar la búsqueda con la consulta, incluyendo esta nueva propiedad, y la veremos en los resultados:

ClientResult<ResultTableCollection> results = null;

using (ClientContext ctx = new ClientContext("http://localhost:41414"))
{
KeywordQuery query = new KeywordQuery(ctx);
query.QueryText = "Item";
query.SelectProperties.Add("MySearchBoolProperty");
SearchExecutor executor = new SearchExecutor(ctx);
results = executor.ExecuteQuery(query);
ctx.ExecuteQuery();
}

if (results.Value.FirstOrDefault() != null)
{
Console.WriteLine("Results: " + results.Value.FirstOrDefault().ResultRows.Count());
Console.WriteLine("Properties per result: " + results.Value.FirstOrDefault()
.ResultRows.FirstOrDefault().Count());
Console.WriteLine("-------------------------------------------------------------");
foreach (var resultRow in results.Value.FirstOrDefault().ResultRows)
{
List<string> props = new List<string>() { "Title","MySearchBoolProperty",
"ContentType", "Rank", "ContentTypeId", "FileExtension", "IsDocument", "FileType" };
foreach (var property in resultRow.Where(i => props.Contains(i.Key)))
{
Console.WriteLine("\t -> {0}: {1}", property.Key, property.Value);
}
Console.WriteLine("-------------------------------------------------------------");
}
}

Y en los resultados veremos los valores introducidos:


image


Y ahora si lo deseamos, podremos crear un filtro contra esta nueva propiedad:


image


Y el resultado:


image


Este enlace puede resultar útil para ver la potencia del Keyword Query Language (KQL):


Keyword Query Language (KQL) syntax reference

Convertir a PDF con Word Automation Services

Vamos a ver un ejemplo sencillo de cómo configurar los Word Automation Services en SharePoint 2013 (servicio que aparece con SharePoint 2010, pero que con la versión 2013 incluye mejoras en la arquitectura y nuevas funcionalidades), y posteriormente convertir documentos Microsoft Word a PDF.

Antes un poco de literatura sobre este servicio:

SharePoint 2013: New Features in Word Automation Services

Word Automation Services Overview

Lo primero de todo es crear el servicio en caso de que no esté ya creado:

image

image

image

Y una vez creado el servicio de aplicaciones y el proxy, comprobamos que los Word Automation Services están en marcha:

image

Ya estaría configurado el servicio para poder desarrollar contra el. Lo siguiente sería atacarlo. En este ejemplo sencillo creamos un job que se dedique a leer de una biblioteca de documentos en concreto y convierta todos los documentos que haya a PDF.

Para poder usar las clases de conversión de documentos (existen 2, ConversionJob para conversiones asíncronas y SyncConverter para síncronas), debemos añadir la referencia a la DLL de Microsof.Office.Word.Server, que encontramos en la ruta: C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI

image

Y con el siguiente código que llamamos desde el método Execute del Job, realizamos la conversión (Al instanciar el ConversionJob, le pasamos el nombre del servicio de Word Automation Services que hemos creado anteriormente):

private void ConvertAllWordToPDF(SPList docList)
{
try
{
ULSLogger.Current.Trace("Converting all Word documents to PDF...");

ConversionJob cb = new ConversionJob("WAService");
cb.Settings.OutputFormat = SaveFormat.PDF;
cb.UserToken = docList.ParentWeb.CurrentUser.UserToken;
cb.AddLibrary(docList, docList);
cb.Start();

ULSLogger.Current.Trace("End Converting all Word documents to PDF...");
}
catch (Exception ex)
{
ULSLogger.Current.Trace("Error converting WordToPDF: " + ex.Message);
}
}

Probamos y vemos que efectivamente, convierte el documento. No tiene por qué hacerlo de forma inmediata, ya que este proceso no lo hace bajo demanda, sino que el Job de Word Automation Services tiene su propio proceso en el que comenzará la conversión cuando corresponda (se puede configurar).


Si por ejemplo queremos ir un poco más allá, y ver el estado de la conversión, así como información del resultado, podemos ampliar el código anterior con algo similar a lo siguiente:


public override void Execute(Guid targetInstanceId)
{
SPWebApplication wapp = this.Parent as SPWebApplication;
SPContentDatabase contentDB = wapp.ContentDatabases[targetInstanceId];

SPList docList = contentDB.Sites.FirstOrDefault().RootWeb.Lists["Documents"];
ConvertAllWordToPDF(docList);
}

private void ConvertAllWordToPDF(SPList docList)
{
try
{
ULSLogger.Current.Trace("Converting all Word documents to PDF...");

ConversionJob cb = new ConversionJob("WAService");
cb.Settings.OutputFormat = SaveFormat.PDF;
cb.Settings.UpdateFields = true;
cb.UserToken = docList.ParentWeb.CurrentUser.UserToken;
cb.AddLibrary(docList, docList);
cb.Start();

ConversionJobStatus status = new ConversionJobStatus("WAService", cb.JobId, cb.SubscriptionId);
while (true)
{
status = new ConversionJobStatus("WAService", cb.JobId, cb.SubscriptionId);
ULSLogger.Current.Trace("Reading status...");
ULSLogger.Current.Trace(String
.Format("Count: {0} | NotStarted: {1} | InProgress: {2} | Succeded: {3} | Failed: {4} | Canceled: {5}",
status.Count, status.NotStarted, status.InProgress, status.Succeeded, status.Failed, status.Canceled));

if (status.Count == status.Succeeded + status.Failed)
{
foreach (var succeded in status.GetItems(ItemTypes.Succeeded))
{
ULSLogger.Current.Trace(String
.Format("Succeded doc: {0} | StartedTime: {1} | CompletedTime {2}",
succeded.OutputFile, succeded.StartTime, succeded.CompleteTime));
}

//Other status

break;
}

Thread.Sleep(1000);
}


ULSLogger.Current.Trace("End Converting all Word documents to PDF...");
}
catch (Exception ex)
{
ULSLogger.Current.Trace("Error converting WordToPDF: " + ex.Message);
}
}

 


Probamos y vemos el resultado que sale en el Monitor ULS.

SharePoint Between Racks © 2012
. Con la tecnología de Blogger.

¡Compártelo!


Estoy en LinkedIn!


Ve mi perfil en LinkedIn!