Integración entre Dynamics 365FO y Azure Bus
En la primera parte de esta serie vimos como trabajar con ficheros con Dynamics 365FO y Azure File Storage.
En este caso, nos olvidaremos de los ficheros y pasaremos a trabajar directamente con mensajes, utilizando para tal objetivo el recurso de Azure Bus, un servicio MaaS (Messaging as a Service) que permite compartir mensajes entre distintas aplicaciones, basado en colas de tipo FIFO (First in First out). Dado que se trata de un servicio asíncrono, en el que incluso pueden intervenir varias aplicaciones, con la caída de alguna de ellas, el servicio seguirá funcionando correctamente, y cuando la aplicación vuelva a estar operativa, podrá leer los mensajes acumulados en la cola sin ningún problema. Además, Azure nos permitirá escalar el servicio en función de las necesidades y la demanda del momento.
Una vez introducido el servicio que utilizaremos, el objetivo de este artículo, como ya apunta el propio título, es realizar una integración para intercambiar información entre Dynamics 365FO y Azure Bus. ¡Vamos a ello!
Crear Azure Bus
En primer lugar, tendremos que crear una instancia de Azure Bus. Para ello, accederemos al portal de Azure y crearemos un recurso del tipo Azure Bus (Bus de servicio, en español). Una vez implementado el recurso, tendremos que crear también, al menos, una cola para almacenar los mensajes.
Descargar Azure Bus Explorer
Para poder gestionar los mensajes de la cola de Azure Bus, necesitaremos descargar la siguiente herramienta:
Para poder utilizar esta herramienta, necesitaremos la cadena de conexión del servicio, la cual podemos obtener en el portal de Azure:
Una vez que tengamos la cadena de conexión, ya podremos utilizar Azure Bus Explorer para conectar con nuestra cola, a través de la opción File/Connect:
Configuración Dynamics 365FO
Al igual que hicimos en la primera entrada de la serie, necesitaremos crear algunas tablas de configuración para almacenar los datos necesarios que nos permitirán trabajar con Azure Bus. Evidentemente, podéis llamar a las tablas de forma distinta, pero tened en cuenta que estos nombres son los que se utilizan posteriormente en el código.
Por una parte, tendremos la tabla AzureParameters, donde guardaremos la cadena de conexión de Azure que hemos recuperado en el punto anterior:
Por otra parte, dispondremos de una tabla adicional, llamada AzureFilesConfig, en la que especificaremos el tipo de información a integrar, como por ejemplo, clientes, y el nombre de la cola de Azure Bus, además de algunas propiedades que nos permitirán estructurar el mensaje de distintas formas, como por ejemplo, el delimitador de registro.
Implementar integración con Azure Bus
Ahora que ya tenemos todo lo necesario, podemos proceder con el código que nos permitirá integrar D365FO con Azure Bus.
En la clase AzureUtils creada en el artículo anterior, añadiremos la siguiente función, que nos permitirá escribir un mensaje en la cola de Azure Bus, a partir de un contenedor o de un Stream.
static boolean createAzureBusMessage(AzureFilesConfig _filesConfig, Name _messageName, container _fileCon = conNull(), System.IO.Stream _stream = null)
{
AzureBusConnector azureBusConnector;
AzureParameters parameters = AzureParameters::find();
str messageName = _messageName;
str outFieldDelimiter = _filesConfig.FieldDelimiter;
str outRecordDelimiter = _filesConfig.RecodDelimiter;
int idx;
boolean ret;
if (_stream)
{
_stream.Position = 0;
}
if (messageName && _filesConfig && (_fileCon || _stream))
{
System.IO.Stream fileStream = _stream;
TextStreamIo file;
if (!fileStream && _fileCon)
{
file = TextStreamIo::constructForWrite(65001);
if (!_filesConfig.FixedPositions)
{
file.outFieldDelimiter(outFieldDelimiter);
}
else
{
file.outFieldDelimiter("");
}
for (idx=1;idx<=conLen(_fileCon);idx++)
{
file.writeExp(conPeek(_fileCon, idx));
}
str filetemppath = File::SendFileToTempStore(file.getStream(), messageName);
fileStream = File::UseFileFromURL(filetemppath);
}
azureBusConnector = new AzureBusConnector();
azureBusConnector.connect(parameters.AzureBusConnectionString, _filesConfig.OrigPath);
azureBusConnector.sendMessageStream(fileStream, messageName);
azureBusConnector.close();
ret = true;
}
else
{
error("@GCN447");
}
return ret;
}
Si compilamos este código obtendremos un error, ya que la variable AzureBusConnector no es un objeto conocido. Este objeto hace referencia a una clase que contiene algunas de las funciones necesarias para comunicarse con Azure Bus, que a su vez utiliza la librería Microsoft.ServiceBus.Messaging
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ServiceBus.Messaging;
namespace AzureBusManager
{
public class AzureBusConnector
{
QueueClient queueClient;
BrokeredMessage message;
public void connect(string _connectionString, string _queueName)
{
queueClient = QueueClient.CreateFromConnectionString(_connectionString, _queueName, ReceiveMode.PeekLock);
}
public void sendMessageString(string _message, string _messageId)
{
message = new BrokeredMessage(_message);
message.MessageId = _messageId;
queueClient.Send(message);
}
public void sendMessageStream(System.IO.Stream _message, string _messageId)
{
message = new BrokeredMessage(_message);
message.MessageId = _messageId;
queueClient.Send(message);
}
public string readMessageStream()
{
message = queueClient.Receive();
System.IO.Stream stream = message.GetBody<System.IO.Stream>();
System.IO.StreamReader reader = new System.IO.StreamReader(stream);
string s = reader.ReadToEnd();
return (s);
}
public string readMessageString()
{
message = queueClient.Receive();
string s = message.GetBody<String>();
return (s);
}
public string getMessageId()
{
return message.MessageId;
}
public long getMessageCount(string _connectionString, string _queueName)
{
Microsoft.ServiceBus.NamespaceManager manager = Microsoft.ServiceBus.NamespaceManager.CreateFromConnectionString(_connectionString);
long messageCount = manager.GetQueue(_queueName).MessageCount;
return messageCount;
}
public void completeMessage()
{
queueClient.Complete(message.LockToken);
}
public void close()
{
queueClient.Close();
}
}
}
Pruebas
Ahora sí, ya estamos en disposición de probar nuestro código, con el que enviaremos un mensaje a Azure Bus desde Dynamics 365FO. Podemos utilizar el siguiente job:
class Job_CreateAzureBusMessage
{
public static void main(Args _args)
{
AzureUtils::createAzureBusMessage(AzureFilesConfig::find(AzureFileType::Customers),
"Mensaje de prueba",
["Cliente 1", "Miquel Vidal"]);
}
}
Si todo ha ido bien, desde Azure Bus Explorer, utilizando la opción Messages, deberíamos ver el mensaje enviado desde D365FO.
Hasta aquí este post, que espero te sirva de ayuda para considerar Azure Bus como una de las opciones a tener en cuenta para las integraciones con Dynamics 365FO.
Non-stop learning!