Este es el tercer y último artículo en el que vamos a hablar de como enviar un JSON con una estructura personalizada a través de Business Events. En el anterior artículo vimos una posible manera de identificar aquellos eventos de negocio que debían someterse a esta nueva estructura por medio del catálogo de eventos. Hoy, veremos finalmente como modificar la estructura del mensaje enviado para estos eventos.
Modificar la estructura del JSON enviado a través de Business Events
El primer paso va a ser definir el contrato de datos para cumplir con el formato del JSON que necesitamos generar. Recordemos que el formato en cuestión debía ser algo similar a esto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ "Id":"06F99161-8C52-4E38-A46F-13918EA48129", "EventTime":"2020-03-24T10:13:36", "EventType":"Project.ERP.JATEventType", "Data": { "BusinessEventId":"JATCustomBusinessEvent", "ControlNumber":5637145326, "EventId":"EA0B3262-EF90-4100-AD0D-3F7E4216A6AB", "EventTime":"/Date(1584617072000)/", "MajorVersion":0, "MinorVersion":0, "JATCustomAttribute":"CustomValue" } } |
Nótese que el contenido del nodo «Data» es el que genera de forma estándar un contrato de datos que herede de la clase BusinessEventsContract por lo tanto, lo que haremos será generar un contrato de datos con los atributos necesarios, siendo «Data» un atributo del tipo JATBusinessEventContract. (Puedes obtener más detalles acerca de como generar estos objetos en este artículo).
Por lo tanto, nuestro contrato de datos personalizado debería ser así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
[DataContract] class JATCustomDataContract { private str eventType; private str eventTime; private str id; private JATBusinessEventsContract data; [DataMember('Id')] public str parmId(str _id = id) { id = _id; return id; } [DataMember('EventType')] public str parmEventType(str _eventType = eventType) { eventType = _eventType; return eventType; } [DataMember('EventTime')] public str parmEventTime(str _eventTime = eventTime) { eventTime = _eventTime; return eventTime; } [DataMember('Data')] public JATBusinessEventsContract parmData(JATBusinessEventsContract _data = data) { data = _data; return data; } public static JATCustomDataContract construct() { JATCustomDataContract customDataContract = new JATCustomDataContract(); customDataContract.parmEventTime(customDataContract.getDateTimeStr()); return customDataContract; } private str getDateTimeStr() { UtcDateTime dateTimeNow = DateTimeUtil::applyTimeZoneOffset(DateTimeUtil::utcNow(), DateTimeUtil::getCompanyTimeZone()); str dateTimeStr = strReplace(DateTimeUtil::toStr(dateTimeNow), ' ', 'T'); return dateTimeStr; } protected void new() { } } |
Una vez que tenemos definida nuestra estructura, solo nos queda recoger el mensaje original y transformarlo para que cumpla con nuestro formato. Después de pasar bastante tiempo debugando y aprendiendo el funcionamiento de los eventos de negocio cuando estos son lanzados, llegué a la conclusión de que la forma más sencilla y menos intrusiva de realizar esta modificación era en el momento de la inserción en la tabla BusinessEventsCommitLog.
El sistema lo que hace es, lanzar el evento de negocio, montar el mensaje a través de los datos recogidos en el contrato de datos, serializar la información para generar el JSON, y una vez está todo listo, insertar dicha información en la tabla anteriormente mencionada. Esta tabla se nutre de los atributos recogidos en la clase BusinessEventsContract, por lo que no podemos cambiar la estructura de la misma si queremos que todo siga funcionando igual. Una vez insertado ahí, un proceso lee los datos, y los manda al extremo correspondiente.
Por ello, la solución se basa en modificar el JSON ya generado, de este modo no interrumpiremos el funcionamiento estándar. Para conseguir eso, lo que hacemos es extender el método insert() de la tabla BusinessEventsCommitLog, y justo antes de realizar la inserción, modificaremos el contenido de ese JSON.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[ExtensionOf(tableStr(BusinessEventsCommitLog))] final class BusinessEventsCommitLogJATCustomEvent_Extension { public void insert() { BusinessEventsTable businessEventsTable; select firstonly JATCustomEvent, JATEventType, Contract from businessEventsTable where businessEventsTable.BusinessEventId == this.BusinessEventId; if (businessEventsTable.JATCustomEvent) { this.SerializedContract = JATSerializeCustomJsonFormat::getSerializedCustomContract(this.BusinessEventId, businessEventsTable.JATEventType, businessEventsTable.Contract, this.SerializedContract); } next insert(); } } |
Con esta extensión, mandaremos a generar nuestro formato personalizado siempre y cuando el Evento que se ha lanzado esté identificado dentro del catálogo de eventos como uno de nuestros eventos personalizados. En caso afirmativo, generamos el nuevo JSON de la siguiente manera:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class JATSerializeCustomJsonFormat { public static str getSerializedCustomContract(BusinessEventsId _businessEventId, EventTypeDescription _eventType, ClassName _businessEventContractClass, str _serializedContract) { JATCustomDataContract customDataContract; BusinessEventsContract businessEventsContract; str customSerializedContract; // Payload businessEventsContract = FormJsonSerializer::deserializeObject(className2Id(_businessEventContractClass), _serializedContract); // CustomContract customDataContract = JATCustomDataContract::construct(); customDataContract.parmId(businessEventsContract.parmEventId()); customDataContract.parmEventType(_eventType); customDataContract.parmData(businessEventsContract); customSerializedContract = FormJsonSerializer::serializeClass(customDataContract); return customSerializedContract; } } |
Básicamente, lo que hacemos es deserializar el JSON para obtener un objeto del contrato de datos con el que estamos trabajando (pasamos por parámetros el nombre del contrato de datos para hacerlo reusable), y una vez que tenemos ese objeto, lo encapsulamos dentro del nuevo contrato, el cual volvemos a serializar y es retornado por el método para que sea insertado en el campo SerializedContract de la tabla BusinessEventsCommitLog.
El resto del proceso permanecerá 100% estándar, por lo tanto no necesitamos extender nada relacionado con la conexión o el tratamiento de los mensajes desde Dynamics 365 hasta el exterior, lo que facilita mucho la gestión de los eventos.
Con estas últimas modificaciones ya estamos preparados para poder consumir nuestros eventos de negocio personalizados desde cualquiera de los extremos que tenemos disponibles.
Como resultado de estos 3 artículos, hemos conseguido generar una solución poco intrusiva y 100% reutilizable, ya que para generar nuevos eventos de negocio que necesiten cumplir con el mismo formato lo único que necesitaremos es decorar dichos eventos con el atributo que generamos en el artículo anterior.
Aquí dejo un enlace a github en el que podéis encontrar la solución completa.
Espero que os resulte útil, y por supuesto estoy abierto a todo tipo de comentarios, críticas y mejoras. ¡Un saludo desde casa!
1 comment / Add your comment below