Request directa a WEB API de CRM Online mediante Azure AD

Cómo hacer una petición directa a la WEB API de CRM para la versión Online mediante Azure AD.

Normalmente cuando queremos hacer una consulta a nuestra base de datos en CRM Dynamics utilizamos la SDK que Microsoft nos proporciona y escribimos un código donde instanciaremos el objeto OrganizationService desde el cual podremos ejecutar un RetrieveMultiple para obtener la información que deseemos de nuestro CRM.

Cuando disponemos de un CRM On Premise podemos también recurrir a la invocación de webservices con autenticación delegada o NTLM, cosa que no podemos hacer en el CRM Online.

Pero ¿qué ocurre si la aplicación que estamos desarrollando no está ideada en C#? En principio no podremos usar la SDK que nos proporciona Microsoft para integrarnos con el CRM. Una solución podría ser utilizar Xamarin para compilar nuestro código en otro lenguaje que necesitemos pero Xamarin no cubre todo el abanico de lenguajes. ¿Cómo podríamos integrarnos con un CRM Online si nuestra aplicación está hecha en PHP, NodeJS, Javascript, etc? ¿Podríamos conectar un CRM Online con otro CRM Online mediante Javascript y sin utilizar un Middleware?, ¿Un sistema tercero podría conectarse con nuestro CRM para enviar información sin necesidad de un Middleware? ¿Un JIRA podría integrarse con nuestro CRM directamente? La respuesta es que sí. Podemos realizar una petición a la API Rest de CRM directamente desde cualquier entorno utilizando el protocolo OAuth2 del Azure Active Directory.

Existe un modo genérico de integrarse con un CRM Online que podemos explotar desde cualquier lenguaje de programación que nos proporcione herramientas para ejecutar peticiones web.

El proceso es el siguiente: primero lanzamos una petición a Azure con nuestros credenciales y la URL del CRM sobre el que queremos ejecutar la query y será el propio Azure el que nos los validará. Si son correctos, Azure nos responderá a nuestra petición con un token. Este token es un “codigo de acceso temporal” a nuestro CRM. Podremos utilizar este código para hacer queries al CRM durante un tiempo limitado (normalmente 3600 segundos) y después caducará. Podremos entonces volver a pedir otro token y repetir el proceso.

Tenemos pues 2 peticiones web: obtener el token y realizar la query en CRM.

Vamos a ver cómo configurarlo paso a paso. Lo primero de todo que tenemos que tener en cuenta es que nuestro Dynamics 365 Online tendrá asociado siempre una cuenta de Azure.

Accedemos a nuestro CRM Online:

Página de inicio de CRM Dynamics 365

Página de inicio de CRM Dynamics 365

 

Una vez logados en nuestro CRM accedemos a Azure mediante el portal de acceso: https://portal.azure.com. El usuario con el que nos hará automáticamente el login será el mismo que nuestro CRM Online.

Página de inicio de Azure

Página de inicio de Azure

 

Accedemos a la sección Registro de aplicaciones mediante la barra de búsqueda superior.

Búsqueda de "Registro de aplicaciones" en azure

Búsqueda de “Registro de aplicaciones” en azure

 

Accedemos a Puntos de conexión en la parte superior.

Puntos de conexiones o "endpoints"

Puntos de conexiones o “endpoints”

 

Bajamos un poco y copiamos la URL del Punto de conexión de token de OAuth 2.0. La URL será del estilo: https://login.microsoftonline.com/d627e6dd-343b-4323-8d8d-b9381c722c7a/oauth2/token

Descripción de puntos de conexión. Token de OAuth 2.0

Descripción de puntos de conexión. Token de OAuth 2.0

 

Bien, esta será la URL a la que tendremos que solicitar el token. Nos la guardamos para más adelante.

Volvemos a Registro de aplicaciones y creamos una nueva aplicación.

Nuevo registro de aplicación

Nuevo registro de aplicación

 

De nombre pondremos “Acceso API CRM”, tipo de aplicación “Aplicación web o API” y URL de inicio de sesión podremos la URL de nuestro Dynamics:

Detalles de la nueva aplicación

Detalles de la nueva aplicación

 

Una vez creada la buscamos entre la lista y la abrimos. Vamos al apartado Propiedades y copiamos el código  Id de aplicación. Este ID lo tendremos que incluir también en petición de token. Lo guardamos junto con la URL.

Propiedades de la nueva aplicación

Propiedades de la nueva aplicación

 

Vamos al apartado Claves:

Claves de la aplicación

Claves de la aplicación

 

Creamos una nueva Clave con descripción “Token” y que expire en 1 año (eres libre de seleccionar lo que más te convenga en este punto). Pulsamos “Guardar” y nos aparecerá el valor (denominado secreto). Debemos copiarlo y guardarlo en este instante pues no tendremos otra posibilidad de volver a conseguirlo:

"Secreto" del token de la nueva aplicación

“Secreto” del token de la nueva aplicación

 

Vamos al apartado Permisos necesarios y pulsamos en Agregar.

Agregar permisos de aplicación

Agregar permisos de aplicación

 

Como API seleccionamos Dynamics CRM Online.

Seleccionar aplicación Dynamics CRM Online

Seleccionar aplicación Dynamics CRM Online

 

Como permisos seleccionamos Access CRM Online as organization users.

Seleccionar permisos delegados

Seleccionar permisos delegados

 

Una vez agregado tenemos que pulsar “Conceder permisos” en la parte superior. Importante: si estás en un Azure de una compañía esta acción la tendrá que realizar un administrador.

Conceder permisos

Conceder permisos

 

Con esto ya tenemos configurado lo necesario en Azure.

Los datos que tendremos por el momento son los siguientes:

Dato Valor Descripción
URL OAuth2.0  https://login.microsoftonline.com/d627e6dd-343b-4323-8d8d-b9381c722c7a/oauth2/token La URL de petición de token
URL CRM  https://micrm.crm4.dynamics.com/ La URL de nuestro CRM
Usuario CRM  ddiaz@micrm.onmicrosoft.com Usuario de nuestro CRM
Password CRM  MiPassw0rd! El password de nuestro usuario
Id Aplicación  b68b3b21-9f40-4923-85e1-7f8e3bc5b746 Id de la aplicación creada en Azure
Secreto  I/sRo1MyR6wRFUS9RgYnCJmCMWiIbq2IPx9evCm45Qc= Disponible solo por 1 año

Con esta información ya podemos ejecutar una query sobre nuestro CRM.

 

Peticiones web

Obtención de token

Los datos que tenemos que incluir en la petición de token son los siguientes

Nombre Key Value
ID Cliente client_id b68b3b21-9f40-4923-85e1-7f8e3bc5b746
URL CRM* resource https://micrm.crm4.dynamics.com/
Usuario* username ddiaz@micrm.onmicrosoft.com
Contraseña* password MiPassw0rd!
Tipo acceso grant_type password
Secreto client_secret I/sRo1MyR6wRFUS9RgYnCJmCMWiIbq2IPx9evCm45Qc=

(*) Los valores tendrán que ser incluidos con encodeURIComponent, por ejemplo el usuario ddiaz@micrm.onmicrosoft.com quedaría como ddiaz%40micrm.onmicrosoft.com

La petición que tendremos que lanzar será

Un ejemplo de petición con datos reales

La respuesta a la petición será como la siguiente:

Y el parámetro en cuestión que nos interesa es el access_token. Con esto ya tenemos el token.

 

Ejecución de query

Una vez que tenemos el token podemos acceder a la WEB API de CRM invocando cualquiera de sus métodos, siempre teniendo en cuenta el nivel de seguridad del usuario para el que hemos obtenido el token. Esto significa que si el usuario ddiaz@micrm.onmicrosoft.com no tiene permisos en CRM para editar contactos, no podrá ejecutar una petición de actualización de un contacto.

Otro punto importante es que mediante este método solo podremos acceder a la WEB API de tipo Rest de CRM y no podremos invocar peticiones directas al OrganizationService con SOAP.

La petición que hagamos tendrá que incluir en el header la propiedad “Authorization” con el valor “Bearer:” + token. Esto será suficiente para obtener acceso a la base de datos de CRM.

El ejemplo que vamos a mostrar es una petición a la API Rest para crear un contacto en CRM.

La petición sería:

 

La URL a donde  enviaremos la petición es de la API Rest de CRM. En particular nos referimos a la entidad “Contacto”. Como vemos, en el header incluimos el token con la palabra “Bearer:” antes. El método POST indica que queremos crear un registro de la entidad. Y en el objeto Data incluimos los logicalName de los campos de la entidad y sus correspondientes valores.

Para sacar partido a la WEB API de CRM existe mucha documentación oficial al respecto para ejecutar cualquier acción sobre nuestra base de datos.

 

Resultados

He implementado un pequeño código de ejemplo en Javascript para hacer la prueba. En particular he utilizado la librería Angular para realizar las peticiones http, pero podría implementarse sin Angular o con cualquier otro framework.

Los archivos que he utilizado son los siguientes:

Archivos del ejemplo de autenticación por OAuth 2.0

Archivos del ejemplo de autenticación por OAuth 2.0

El framework de Angular lo podéis descargar del sitio oficial. Los archivos indexOauth.html y js_api_rest_oauth.js los detallo a continuación:

indexOauth.html:

js_api_rest_oauth.js:

El resultado de la ejecución del código anterior genera la siguiente respuesta:

Resultados de ejecución del ejemplo

Resultados de ejecución del ejemplo

Si lo ejecutáis desde vuestro PC en local es posible que obtengáis el error de No ‘Access-Control-Allow-Origin’. Para solucionarlo existen extensiones de Google Chrome que lo resuelven.

Como veis hemos creado un contacto en CRM a través de un token obtenido mediante OAuth del Azure Active Directory ejecutando una petición a la WEB API.

Espero que os sirva!

 

Obtener el nombre del workflow padre con ParentContext

Cuando desplegamos un plugin o un workflow en nuestra instancia de CRM Dynamics estamos activando un flujo de trabajo que se ejecutará ante un determinado evento. En el caso del workflow podemos configurar mediante el menú de edición de Dynamics unas condiciones extra que se deben de dar para que se ejecute el código –como podría ser que determinado campo del registro modificado esté valorizado-.

Podría darse el caso de que este registro del que hablamos sea modificado por el usuario mediante un formulario de CRM, y además también podría ser modificado mediante la ejecución de otro workflow o plugin de, por ejemplo, actualización de datos nocturnos. Y rizando el rizo podemos suponer que un workflow puede llamar a otro, y este a otro, y así repetidas veces, pudiendo encontrar problemas si no controlamos bien el contexto en el que se ejecuta nuestro código.

En la ejecución de un Workflow o plugin siempre podemos obtener el objeto Context que vendrá heredado y que contendrá información sobre la profundidad –accesible mediante la propiedad Depth del objeto- además de otros parámetros de interés.

Cuando la profundidad es igual o mayor a uno implica que la ejecución de nuestro código ha sido invocada desde otro workflow o plugin. Cuando esto ocurre,  podremos acceder al ParentContext que será un objeto del mismo tipo pero que contendrá información del contexto del workflow que precede al nuestro que incluso podría darse el caso de que sea el mismo workflow.

La idea es poder obtener el nombre literal de ese workflow padre para poder poder condicionar la ejecución de nuestro workflow mediante un if.

Nombre literal del workflow en la entidad "Trabajos del sistema"

Nombre literal del workflow en la entidad “Trabajos del sistema”

Como hemos dicho, el ParentContext contiene información del contexto del workflow invocador de nuestro workflow, y entre otros datos contiene el parámetro CorrelationId que sería el id único del registro de tarea del sistema creado por este workflow. Con este id seremos capaces de obtener el nombre de éste workflow y condicionar la ejecución, como se indica en el siguiente ejemplo:

Peticiones SOAP con AngularJS en CRM Dynamics

Soap request con AngularJS en Microsoft Dynamics CRM

La librearía AngularJS nos proporciona un potente framework de herramientas y procedimientos con los que implementar páginas web basadas en MVC. Toda esta funcionalidad se puede también utilizar dentro de nuestros recursos web –web resources- en CRM. En este post vamos a ver cómo implementar llamadas Soap con AngularJS y encadenar respuestas con los objetos promises.

Como sabemos, cuando se hace una query a CRM desde el frontal web utilizando la API debemos trabajar con funciones Callback –ya sea para peticiones utilizando la librería SDK.Rest o peticiones Soap a través del Organization Service- y en determinadas ocasiones, cuando tenemos que encadenar varias queries una detrás de otra el modo común de realizarlo es anidando Callbacks:

Con la librería AngularJS, los objetos promises que veremos a continuación y los servicios “$http” y “$q”, este ejemplo anterior se transformaría en algo del estilo:

Como vemos, el código queda más limpio en el segundo caso. Además de dejar el código más bonito la librería angular nos ofrece una mayor libertad para controlar procesos asíncronos permitiéndonos acceder al proceso de carga o ejecutando varias peticiones en paralelo.

Recordemos que para realizar una llamada Soap necesitamos tres cosas: la URL del endpoint, la acción que vamos a utilizar, y el cuerpo del mensaje. Con estas tres cosas podemos realizar la petición Soap con AngularJS.

Para construir la llamada utilizaremos el servicio “$http” de Angular como se muestra en el ejemplo.

La propiedad data del objeto response en el primer then del método RequestData contendrá el resultado de la petición. En este caso el cuerpo del mensaje es una petición de RetrieveMultiple con un filtro y nos devolverá las cuentas cuyos nombres empiecen por “A”. Recordar que esta es una respuesta http y por defecto el endpoint de CRM que estamos atacando nos devolverá mensajes serializados en XML -no es posible cambiar la respuesta a JSON como sí permite la API REST OData-. Para deserializar el XML podemos recurrir a herramientas externas o implementar nuestro propio deserializador utilizando la versión reducida de jQuery que trae angular, analizando los nodos. Yo he utilizado como base este ejemplo con una pequeña modificación.

El resultado de la ejecución nos mostraría un array de todos los Ids de las cuentas que empiezan por “A” en nuestro CRM.

Ids de todas las cuentas de CRM que empiezan por “A”

Pero donde realmente se puede sacar partido a esta librería es en el uso del servicio “$q”. Este servicio nos permite añadirle N objetos promesa y ejecutarlo. El código que esté dentro del then sucesivo se ejecutará cuando todas las peticiones hayan terminado y nos devolverá N respuestas, una para cada una de las peticiones ejecutadas. Esto es una gran noticia puesto que nos avisará cuando todas las peticiones tengan respuesta, y no se ejecutará cada vez que termine una de ellas. Así permitirá controlar el flujo de información de nuestro código de una manera mucho más limpia y clara.

Siguiendo con el ejemplo anterior, imaginemos que después de obtener todas las cuentas que empiecen por “A”, para cada una de ellas queremos obtener el nombre de todos los contactos asociados a esas cuentas.

El resultado de esta ejecución nos proporcionaría el siguiente array de nombres:

Nombres de todos los contactos que pertenecen a alguna de las empresas del ejemplo anterior

Nombres de todos los contactos que pertenecen a alguna de las empresas del ejemplo anterior

Estos son sólo dos ejemplos de lo que esta librería puede ofrecernos en CRM Dynamics  pero realmente las posibilidades son infinitas cuando juntamos peticiones Soap con AngularJS.

String connection CRM

 

String connection

Las string connections son variables de tipo string que contienen los datos necesarios para realizar una conexión a un entorno. Se utilizan mucho para, por ejemplo, conectarse a una base de datos. Estas cadenas de texto contienen todos los datos necesarios para que el cliente que realiza la petición sepa a qué base de datos debe conectarse y bajo qué usuario y password debe realizarlo. Son muy útiles porque nos permiten definir todos los datos necesarios para conectarse en una única variable, lo que simplifica el mantenimiento de la aplicación.

CRM Dynamics no es distinto y nos ofrece la posibilidad de conectarnos a una instancia de CRM únicamente indicando la string connection de esa instancia. El procedimiento ha cambiando un poco desde la versiones antiguas de CRM y la nueva versión 365 pero en esencia es igual. Vamos a ver cómo utilizar una string connection desde una aplicación hecha en C#:

SDK CRM 2011, 2013, 2015 y 2016

 

SDK CRM 365

 

Las diferencias entre las versiones son simplemente en el objeto que se instancia y de qué clase proviene. En las versiones antiguas se generaba la interface IOrganizationService desde el objeto OrganizationService mientras que en la nueva versión 365 el IOrganizationService se instancia desde el objeto CrmServiceClient del namespace Microsoft.Xrm.Tooling.Connector. También observar que la string connection para 365 tiene el parámetro extra de Authtype.

Cómo construir nuestra propia String Connection

Las String Connection por desgracia no son siempre iguales. En función del tipo de instancia que tengamos, o del tipo de autentificación se construirán de un tipo u otro. Vamos a ver qué parámetros se pueden incluir y algunos ejemplos:

 

Nombre de parámetro Parámetro Descripción
Server, Url, or Service Uri Url, Server, ServiceUri  La URL de nuestro CRM.

  • Si es una instancia on premise, la URL debería incluir la organización. Por ejemplo http://servidorcrm:puerto/nombre-organizacion.
  • Si es una instancia online, la URL será la que utilizamos para acceder. Por ejemplo: http://nuestra-organizacion.crm4.dynamics.com/

Para la string connection, funcionará igual si utilizamos la palabra Url, Server o ServiceUri

Domain Domain  El dominio de nuestra organización. Estaría relacionado con el Active Directory si estamos hablando de una instancia on premise. Para los online no es necesario incluir este parámetro.
Username or User ID Username Nuestro nombre de usuario.
Password Password Nuestro password. Podemos incluir dobles comillas al inicio y al final si nuetro password incluye espacios u otros caracteres especiales.
Timeout Timeout Por defecto el timeout de las conexiones a CRM son 2 minutos, pero si lo deseamos podemos aumentar o reducir esta cantidad. El formato sería timespan del tipo “hh:mm:ss”.
 Authtype Authtype  Necesario solo para instancias CRM 365. Si tenemos un CRM Dynamics 365 la string connection deberá incluir este parámetro. Los valores que puede tomar son:

  • Authtype=”Office365″ si nuestro CRM 365 es Online
  • Authtype=”AD” si nuestro CRM es on premise y validamos los credenciales contra el Active Directory
  • Authtype=”IFD” si nuestro CRM es on premise y validamos los credenciales mediante IFD

Los parámetros deberán incluirse uno detrás de otro separados por punto y coma en formato texto dentro de nuestra String. No son necesarias las comillas para indicar un parámetro a no ser que el valor de éste incluya carácteres especiales o espacios. Para las versiones on premise es posible también conectarse utilizando seguridad integrada de Windows, no incluyendo los parámetros Username y Password en la string connection. Si hacemos esto, la ejecución de las peticiones se realizará con el usuario que esté ejecutando la sesión de windows.

Algunos ejemplos:

CRM 365 online

“ServiceUri=https://ourorganization.crm4.dynamics.com/; Username=name@ourorganization.onmicrosoft.com; Password=OurPassw0rd; Authtype=Office365;”

 

CRM 365 on premise

“ServiceUri=http://ipcrm:5555/OrganizationName; Domain=ourdomain; Username=username; Password=OurPassw0rd; Authtype=AD;”

 

CRM 2011/2013/2015/2016 online

“ServiceUri=https://ourorganization.crm4.dynamics.com/; Username=name@ourorganization.onmicrosoft.com; Password=OurPassw0rd;”

 

CRM 2011/2013/2015/2016 on premise

“ServiceUri=http://ipcrm:5555/OrganizationName; Domain=ourdomain; Username=username; Password=OurPassw0rd;”

 

CRM 365 on premise con seguridad integrada

“ServiceUri=http://ipcrm:5555/OrganizationName; Authtype=AD;”

 

CRM 2011/2013/2015/2016 on premise con seguridad integrada

“ServiceUri=http://ipcrm:5555/OrganizationName;”

 

Fuentes: Microsoft, Ax3Group

Descargar un Workflow o Plugin de CRM

En este post vamos a ver cómo descargar un Workflow o Plugin registrado en CRM. Sería algo así como el proceso inverso que realiza el Plugin Registration Tool que trae la SDK de CRM. Mediante esta herramienta podemos registrar (o subir) ensamblados DLL a CRM pero no se nos permite descargarlos.

Para hacer la prueba vamos a crear un Workflow muy simple, lo vamos a registrar y a continuación lo vamos a descargar. El Workflow únicamente escribirá un nuevo registro dentro de una entidad de Log denominada new_log.

Además, para tener una pequeña verificación de que el Workflow que nos descargaremos luego sea el mismo que hemos registrado voy a darle una versión de compilado a la DLL con el valor 3.1.4.1.

Versión compilado Visual Studio

Versión compilado Visual Studio

 

Recordad que además para que un Workflow pueda ser registrado debe contener firma. En las propiedades del proyecto, en el apartado Firma (Signing) añadimos una nueva firma.

Añadir firma a un Workfow

Añadir firma a un Workfow

Compilamos y obtenemos la DLL con nuestro Workflow.

DLL del Workflow compilado

DLL del Workflow compilado

Abrimos el Plugin Registration Tool y registramos nuestro Workflow en nuestra organización.

 Workflow registrado en CRM

Workflow registrado en CRM

Hasta aquí sería el trabajo que solemos hacer para cargar un ensamblado en CRM. Ahora vamos a ver cómo descargarlo. Lo primero de todo es entender cómo se guardan en CRM los ensamblados. Un ensamblado se guarda en la base de datos del mismo modo que cualquier otro registro cuando seleccionamos este modo de registro en el Plugin Registration Tool en la opción Location : Database, que es la opción por defecto. En este caso cuando registramos una DLL en CRM se creará un registro que contendrá, entre otros datos, el contenido del ensamblado. La entidad donde se guardan los ensamblados tiene como nombre lógico (logical name) pluginassembly y, como el resto de entidades, cada registro tendrá un ID único. Para conocer el ID debemos ir a CRM y mediante una búsqueda avanzada a la entidad Ensamblados de Complementos encontraremos el nuestro Workflow. El ID lo podemos obtener abriendo la consola del navegador y localizando la linea en el código.

Obtener un ID de un registro mediante búsqueda avanzada

Obtener un ID de un registro mediante búsqueda avanzada

Ahora, teniendo la entidad y el ID único podemos hacer un Retrieve. Los campos que debemos descargar son el nombre (name) y el contenido del ensamblado (content). Este segundo campo contiene el contenido de la DLL codificado en Base 64. Desde C# es sencillo decodificarlo mediante la clase Convert.

Con todo esto ya podemos descargar y guardar en un archivo la DLL, como en el siguiente ejemplo:

Si ejecutamos ese comando y abrimos la carpeta donde está el ejecutable encontraremos la DLL y podremos comprobar la versión.

DLL descargada con su versión

DLL descargada con su versión

 

SDK Rest Retrieve con Expand

La librería SDK.REST es la mejor herramienta que tenemos para hacer queries a CRM desde Javascript. Esta librería ofrece una serie de métodos con los cuales podemos interactuar con la Api REST de CRM. Uno de esos métodos es el Retrieve que incluye el parámetro Expand que vamos a analizar.

Con el método Retrieve podemos obtener un registro de CRM indicándole la entidad y el Id del mismo. Además es siempre recomendable que le indiquemos los campos que necesitamos puesto que por defecto te devolverá todos, cosa que en la mayoría de los casos no necesitaremos y además ahorraremos recursos.

La definición del método RetrieveRecord según la librería es el siguiente:

El primer y el segundo parámetro son el Id y entidad del registro que queremos recuperar. Es importante notar que el nombre de la entidad es el Nombre de Esquema (Schema name) que se escribe con mayúsculas/minúsculas según está definido en la solución.

El tercer parámetro son los campos que queremos recuperar. En este caso sería una cadena de texto con los nombres (de esquema) de los campos que queremos obtener, separados por comas.

Las dos ultimas, son las funciones Callback de Exito/Error que se ejecutarán si el registro se ha devuelto bien o si se ha encontrado algún error respectivamente.

Finalmente, como cuarto parámetro tenemos el Expand. El Expand es una cadena de texto donde se incluirán los nombres de las relaciones que queremos expandir siempre en referencia al registro que estamos pidiendo. Se podrán incluir relaciones 1:N y N:1. En cada caso obtendremos un objeto distinto como resultado.

Relaciones 1:N de la entidad Account

Relaciones 1:N de la entidad Account

Es interesante recalcar que con los Expands no se indican qué campos de la entidad expandida quieres, sino que te devuelve todos. Es por esto que aunque en la definición de la librería diga que se pueden hasta expandir 6 relaciones, en mi opinión no es nada recomendable puesto que te devolverá en una sola llamada un volumen muy grande de datos [ 1 registro padre + (N1 registros hijos relación 1 * M1 campos cada registro)  + (N2 registros hijos relación 2 * M2 campos cada registro) + …  ]. Si multiplicamos esto por cada usuario de CRM que esté trabajando podemos sobrecargar el sistema.

Expand con relación 1:N

Un ejemplo sería obtener una cuenta y además todos los contactos asociados a la cuenta. Como es lógico, cuando hacemos esto obtenemos 1 resultado padre, la cuenta, y N hijos, todos los contactos relacionados con esa cuenta. La petición y deserialización sería del siguiente modo:

Como vemos en la siguiente imagen, el objeto response que nos devuelve como parámetro en el SuccessCallBack tiene primero los campos pedidos en el Select del registro padre (cuenta) y además, colgando del objeto contact_customer_accounts.results tenemos un Array con cada uno de los resultados hijos (contactos) y todos sus atributos.

Estructura del objeto response en un Retrieve con Expand 1:N

Estructura del objeto response en un Retrieve con Expand 1:N

Para recorrer el array de respuesta lo haremos como en se muestra en el código superior, con un bucle For que recorra todos los results de la expansión.

Expand con relación N:1

Ahora, en el caso opuesto, vamos a expandir una relación N:1. Esto es, queremos el padre del registro que estamos solicitando. Como no puede ser de otra manera, en este caso solo esperamos que nos devuelva un resultado y no N como en el ejemplo anterior.

Siguiendo con el ejemplo anterior, vamos a expandir la relación de “Contacto principal” de una Cuenta.

El código quedaría algo del estilo:

En este caso, al disponer de un solo resultado en la expansión, se ahorra el results del objeto account_primary_contact dentro del objeto response.

Estructura del objeto response en un Retrieve con Expand N:1

Estructura del objeto response en un Retrieve con Expand N:1

Expand con relación N:N

Desconozco si es posible expandir una relación N:N pero todas las pruebas que he hecho no han funcionado. Si alguien sabe cómo hacerlo le agradecería que indicase cómo en los comentarios!

Mezclando expansiones

Como hemos indicado con anterioridad, es totalmente posible expandir varias relaciones en la misma petición (hasta 6) y por cada una de ellas obtendremos un objeto colgando del response con el nombre de la relación. Si es 1:N además éste contendrá un Array denominado results con todos los hijos del registro.


Para terminar, indicar con la extensión para Chrome HUDCRM, en la pestaña “Query constructor” podéis obtener todos estos códigos mostrados en el post de manera muy sencilla.

Ejemplo constructor de queries SDK.REST con la extensión para Chrome HUDCRM

Ejemplo constructor de queries SDK.REST con la extensión para Chrome HUDCRM

 

Parametros que se envian a Web Resource desde formulario

Cuando creamos un Web Resource desde el menú de edición del formulario de la entidad, podemos configurar que se envíen parámetros al mismo en la iniciación del formulario. Esto se consigue marcando la casilla “Pasar código tipo de objeto de registro e id. Único como parámetros”.

Configuración de Web Resource para pasar parámetros desde el formulario

Configuración de Web Resource para pasar parámetros desde el formulario

Cuando tenemos esta casilla activada durante la carga del Web Resource en nuestro formulario se invocará la URL y se añadirán algunos parámetros del contexto donde se está abriendo ese Web Resource. Esto es algo bueno puesto que mediante este contexto de información podremos desarrollar un Web Resource personalizado, por ejemplo, para el cliente que se esté viendo en ese momento.

Los parámetros que se envían por defecto cuando seleccionamos esta casilla son los siguientes:

# Parámetro Descripción
1 OrgLCID Id del código de lengua de la organización
2 UserLCID Id del código de lengua del usuario
3 Id Id del registro que estamos cargando
4 Orgname Nombre de la organización
5 Type Tipo de formulario.  0 = Undefined, 1 = Create, 2 = Update, 3 = Read Only, 4 = Disabled, 5 = Quick Create, 6 =  Bulk Edit, 11 = Read Optimized
6 Typename Nombre de la entidad donde se ha abierto el WR

Un ejemplo de URL completa para nuestro sería el siguiente:

new_prueba_web_resource?OrgLCID=3082&UserLCID=3082&id={42DCC3D2-7339-E611-80D6-C4346BAC8D78}&orgname=NuestraOrganizacion&type=2&typename=contact

El modo en el que podemos capturar estos parámetros desde nuestro javascript se ha indicado ya en este post antiguo. En este caso el proceso sería similar.

CRM también nos permite enviar parámetros personalizados introduciéndolos en el cuadro de texto que está encima del check indicado con anterioridad, en las propiedades del Web Resource. Si fuese este el caso, estos parámetros se enviarán a continuación de los ya indicados.

Podéis ver los parámetros que se han enviado a un Web Resource fácilmente con la extensión HUDCRM.

Obtener parámetros de carga de un web resource desde HUDCRM

Obtener parámetros de carga de un web resource desde HUDCRM

Obtener el OrganizationService heredado del USD

Cuando queremos meter algún tipo de funcionalidad específica en nuestro USD lo realizamos mediante un Custom Hosted Control. Este control se realizaría desde Visual Studio extendiendo la clase DynamicsBaseHostedControl del compilado Microsoft.Crm.UnifiedServiceDesk. Esta clase a su vez implementa varias interfaces como son IDesktopUserActionsConsumer, IUsdControl y ISessionInfoConsumer. Estas interfaces incluyen funciones  como el DoAction –que se utiliza para recibir ActionsCalls del USD en nuestra clase- , el DesktopReady –que se ejecuta cuando el USD ha cargado-  o el NotifyContextChange –evento de cambio en alguna variable del contexto- entre otras. Dentro de todas estas funciones es muy probable que necesitemos interactuar con nuestro CRM. Como siempre, la API de CRM nos permitirá hacerlo utilizando el objeto OrganizationService. Como ya sabréis este objeto se puede instanciar utilizando una cadena de conexión con la IP de nuestro CRM y el usuario y contraseña de un usuario del CRM.

Pero puesto que en USD ya nos hemos tenido que identificar para poder acceder al mismo introduciendo unos credenciales al inicio –o en su defecto utilizando los credenciales del Active Directory- no sería práctico volver a instanciar el objecto OrganizationService puesto que deberíamos volver a preguntar al usuario sus credenciales.

El USD por dentro utiliza un objecto OrganizationService de igual modo que cuando realizamos un programa nosotros. Este objeto OrganizationService se instancia de los credenciales iniciales que se introducen en la pantalla de inicio del USD –la clásica pantalla azul de USD- y se utiliza internamente para descargar toda la configuración del agente al PC desde donde se está ejecutando el USD.

Probablemente existan varios métodos para obtener este objeto instanciado en nuestro código. Yo únicamente conozco dos.

El primero es heredar en nuestra clase la clase AifServiceBase. Esta clase que está en la librería Microsoft.Uii.AifServices, en el contexto de USD hereda el objeto OrganizationService para poder utilizarlo. El esquema que yo utilizaría sería, por un lado, la clase principal de la dll -la que incluiremos como Hosted Control en nuestra configuración- que hereda del  DynamicsBaseHostedControl  y por otro lado una clase que actúe de interface entre USD y CRM que herede del AifServiceBase. Dentro de la primera clase instanciaremos la segunda una sola vez pudiendo acceder al objeto a partir de ese momento.

Ejemplo estructura clases Custom Hosted Control con AifService

Ejemplo estructura clases Custom Hosted Control con AifService



Como lado negativo de este método comentar que a mi únicamente me ha funcionado con la versión 1.2 de USD y sospecho que es debido a que el AifService requiere la dll Microsoft.Crm.Sdk.Proxy que únicamente está incluida en la SDK de 2015 y por algún motivo no funciona en versiones de compilados superiores.

El segundo método y el más sencillo es obtener el IOrganizationService directamente del objeto Global Manager.

El USD siempre requiere de tres objetos principales y que son, podríamos decir, obligatorios: El Global Manager, el  Connection Manager y el Panel Layout. La idea es obtener en nuestra clase el Global Manager del USD y extraer el OrganizationService de dentro del objeto.

Para ello únicamente necesitamos conocer el nombre del Hosted Control de tipo Global Manager. El nombre lo obtenemos de la configuración del Unified Service Desk de nuestro CRM. Si durante la instalación del USD seleccionamos la opción de incluir datos de ejemplo, este Hosted Control ya estaría creado en nuestro primer USD. Si por el contrario hicimos una instalación limpia, tuvimos que crearlo nosotros mismos en algún momento. Lo que necesitamos es el nombre del Hosted Control, esto es, el string que se ve en la configuración.

Nombre del Hosted Control Global Manager

Nombre del Hosted Control Global Manager

En nuestro caso el Hosted Control se llama “Global Manager” por lo que para obtener el OrganizationService simplemente deberíamos de ejecutar la siguiente línea:

 

 

Variable window.IsUSD = true que introduce USD sobre el header

Una de las funcionalidades que más destaca del Unified Service Desk es la integración nativa con los formularios de CRM mediante la navegación a una URL de nuestra instancia. Además de esto, el USD nos permite por lo general navegar a cualquier otra dirección que deseemos mediante la UIIAction Navigate. Esto nos permitirá abrir aplicaciones web externas dentro de nuestro USD. ¿Es posible desde una aplicación web saber si la navegación se ha producido dentro de una pestaña del USD? La respuesta es sí: mediante la variable window.IsUSD.

El Unified Service Desk se toma la molestia de introducir en el Header de cada web que se carga un pequeño fragmento de código Javascript como el siguiente:

 

 

De modo que mediante el acceso a esta variable podremos saber si nuestra aplicación web -o nuestro Web Resource incrustado en un formulario de CRM- ha sido visitada desde un USD.

Variable IsUSD en el Header de Google

Variable IsUSD en el Header de Google

 

En el caso de que estemos navegando sobre un formulario de CRM, el USD también incluirá esta variable en el Header de los Iframes que contiene (Iframes normales o Webresources).

Variable IsUSD en el Header de Bing abierto en un Iframe de un formulario CRM

Variable IsUSD en el Header de Bing abierto en un IFrame de un formulario CRM

 

Variable IsUSD en el Header de un Web Resource de un formulario CRM

 

Pero, ¿en qué situaciones podríamos aprovecharnos de este hecho?

Las razones por las cuales necesites saber si un USD ha abierto tu aplicación web pueden ser muchas, pero existe un gran motivo por el cuál esa variable está ahí.

De modo nativo, el USD nos avisa de eventos generados en cualquier formulario. Un ejemplo sería un evento OnSave de un formulario. Este evento se envía al USD y éste lo recibe pudiendo generar con él una Action Call que derive en cualquier otra acción o ejecución de código. El método que utiliza CRM para “avisar” al USD de que en el formulario se ha producido un evento de guardado es mediante la ejecución de un comando Javascript del tipo:

 

Cuando el USD detecta que queremos navegar a una web del dominio event lo interpretará como que esa página web le está avisando de un evento y no realizará la navegación.

Y aquí está la clave de la variable IsUSD. Si incluimos una linea como la anterior en un Web Resource y abrimos el formulario desde un navegador y no desde el USD, el navegador ejecutará esa orden produciendo que la página navegue a esa “URL”. El resultado será que nuestro navegador nos abrirá una ventana de una página web totalmente ajena a nuestro proyecto y que por supuesto mostrará publicidad de cualquier tipo.

Esta aquí uno de los motivos por los cuales Microsoft ha incluido esta funcionalidad de inyectar sobre cualquier web una variable que nos avise de que la navegación se está produciendo desde USD y no desde otro navegador. Mediante la verificación de esta variable podremos ahorrarnos ejecutar esa orden de evento si la navegación está fuera del USD añadiendo a nuestro código la siguiente comprobación:

Con ello podremos controlar este hecho en nuestras aplicaciones web

Navegando en el mismo formulario con y sin USD

Navegando en el mismo formulario con y sin USD

 

Instalación Unified Service Desk en entorno CRM y PC

El Unified Service Desk es una herramienta que nos ofrece Microsoft para todos los usuarios de CRM que nos brinda la oportunidad de integrarnos con nuestro entorno desde una aplicación de escritorio, que además es 100% administrable desde nuestra configuración en CRM. En este post veremos como realizar la instalación en nuestro CRM.

La filosofía de USD es la siguiente: En tu PC tendrás instalada una DLL que incluya el código fuente de un Botón (por ejemplo), con su interfaz gráfica, su propiedades, métodos y eventos. Ahora bien, si quieres que en tu USD aparezca un botón tendrás que ir a CRM e indicarlo en la configuración definida para ti.
Cuando inicia el USD, siempre lo hará con las credenciales de un usuario (o agente) de CRM. Este agente, por lo general tendrá definido en su ficha de agente de CRM una configuración, y dentro de esa configuración en CRM estará definido un botón. Así pues, cuando abras el USD toda esta información relativa a tu configuración se descargará y se guardará en caché. Si en esa configuración (definida en CRM) se indica que tu USD tiene un botón, entonces USD te pintará un botón. Además ese botón tendrá todas las características que le hayas indicado en la propia configuración del botón en CRM como pueden ser su texto para mostrar, acciones asociadas, eventos, etc.

El ejemplo indicado trata de un botón pero existen muchos otros tipos de objetos que se definen desde CRM y que cambian el comportamiento del USD como pueden ser navegadores, paneles, barras de botones, imágenes etc.

Sobre esto podemos hablar y extendernos mucho, no obstante para este post nos interesa sólo saber que existen dos mitades que necesitan la una de la otra y que completan el USD: DLLs en nuestro PC y configuración en nuestro CRM.

Partes fundamentales USD instalación

Partes fundamentales USD instalación

Vamos entonces a instalar las dos partes. Lo primero de todo que necesitamos es descargarnos los paquetes de la página. Los paquetes necesarios son el PackageDeployer y la versión de USD que queramos instalar en nuestro PC (32 o 64bits).

Descargamos los paquetes y los descomprimimos.

Primero vamos a instalar el PackageDeployer. Este paquete lo que hará será instalar en nuestro CRM todas las entidades que son necesarias para definir los elementos del USD, además de sus relaciones, reglas, imagenes etc. Además nos creará los formularios en CRM para interactuar con la configuración de nuestro USD y poder definir cada uno de sus elementos.

Abrimos el archivo CRM2016-USD-2.1.0-PackageDeployer.exe.

Instalacion Package Deployer Step 1

Instalacion Package Deployer Step 1

Click en aceptar y Continue

Instalacion Package Deployer Step 2

Instalacion Package Deployer Step 2

Tendremos que seleccionar una carpeta donde extraer los archivos de instalación. En esta carpeta no se instalará nada, solo es una carpeta de extracción para la instalación.

Instalacion Package Deployer Step 3

Instalacion Package Deployer Step 3

Una vez que se termine de extraer se nos abrirá el instalador

Instalacion Package Deployer Step 4

Instalacion Package Deployer Step 4

En la siguiente pantalla nos pedirá un login. El proceso es distinto si nuestra instancia es online u onpremise. Si es el caso de una instalación onpremise el login debería ser parecido al de la siguiente imagen:

Instalacion Package Deployer Step 5. Login on premise

Instalacion Package Deployer Step 5. Login on premise

Por el contrario, si nuestro CRM es online solo debemos indicar nuestro usuario y contraseña, el mismo con el que nos logueamos en el portal de Microsoft

Instalacion Package Deployer Step 5. Login online

Instalacion Package Deployer Step 5. Login online

Una vez iniciada sesión nos pedirá que seleccionemos un tipo de instalación. Esta instalación es una instalación nueva de cero. Eso significa que en el CRM que queremos instalar el Unified Service Desk no hay ninguna otra versión previa instalada. Si fuese así, deberíamos de actualizar y no instalar de cero.

Instalacion Package Deployer Step 6. Selección tipo instalación

Instalacion Package Deployer Step 6. Selección tipo instalación

Aceptamos los términos de la licencia

Instalacion Package Deployer Step 7

Instalacion Package Deployer Step 7

Aceptamos en la siguiente ventana y comenzará la instalación

Instalacion Package Deployer Step 8

Instalacion Package Deployer Step 8

La primera parte de la instalación es recapitular toda la información que hemos introducido

Instalacion Package Deployer Step 9

Instalacion Package Deployer Step 9

La segunda parte, y la más larga, es la carga en el CRM de las soluciones con sus entidades, formularios y relaciones.

Instalacion Package Deployer Step 10. Instalando

Instalacion Package Deployer Step 10. Instalando

Este proceso puede durar varios minutos en función de tu conexión. Al final deberíamos tener algo como lo siguiente:

Instalacion Package Deployer Step 10. Instalación completada

Instalacion Package Deployer Step 10. Instalación completada

Una vez terminado esto, finalizamos la instalación

Instalacion Package Deployer Step 11

Instalacion Package Deployer Step 11

Una vez terminada la instalación podemos comprobar que se nos ha habilitado un menú en la barra superior de CRM, en el menú de configuración, donde podremos acceder a la configuración de USD.

Acceder al menú de configuración de Unified Service Desk desde CRM

Acceder al menú de configuración de Unified Service Desk desde CRM

Nota: Si no ha aparecido el botón es probable que sea porque tenías el CRM abierto durante la instalación. La barra superior de menús no se recarga al navegar entre formularios por lo que para que aparezca prueba a recargar la página entera mediante Control + F5.

Nota:  una vez terminada esta instalación podemos eliminar la carpeta de extracción que creamos en el segundo paso.

Ya tenemos la primera mitad del USD instalada. Ahora necesitamos que esta configuración de CRM sea efectiva en nuestra aplicación de escritorio.

Procedemos a instalar la segunda parte. Esta instalación deberá realizarse en todos y cada uno de los ordenadores en los que un usuario quiera acceder al CRM mediante el Unified Service Desk. También puede instalarse en un escritorio virtual VDI al que accederán distintos usuarios.

Abrimos el archivo CRM2016-USD-2.1.1-amd64.exe

Instalación Unified Service Desk. Step 1

Instalación Unified Service Desk. Step 1

Dejamos el directorio por defecto para la instalación

Instalación Unified Service Desk. Step 2

Instalación Unified Service Desk. Step 2

Para que Unified Service  Desk funcione correctamente es necesario tener también instalados el .NET Framework 4.5.2 y el Windows Identify Foundation. Ambos están incluidos en el instalador y si los seleccionamos nos los instalará antes del USD.

Instalación Unified Service Desk. Step 3

Instalación Unified Service Desk. Step 3

Comenzamos la instalación

Instalación Unified Service Desk. Step 4

Instalación Unified Service Desk. Step 4

Cuando termine esta instalación, de modo automático nos abrirá el Unified Service Desk. La imagen que se ve a continuación es la pantalla inicia del USD donde, pulsando sobre Cambiar credenciales nos permitirá configurar a qué CRM queremos que nuestro USD se conecte.

Ventana de inicio Unified Service Desk

Ventana de inicio Unified Service Desk

Las opciones de login son las mismas que en el Package deployer. Podemos conectarnos al CRM online u onpremise.

Ventana de login Unified Service Desk. On premise

Ventana de login Unified Service Desk. On premise

Ventana de login Unified Service Desk. Online

Ventana de login Unified Service Desk. Online

Una vez que introducimos los credenciales e iniciamos sesión el USD se quedará cargando y finalmente nos mostrará la ventana principal. Es en este periodo de carga después de iniciar sesión cuando se produce en background la operación de descarga de información del CRM donde hemos indicado, y descarga de configuración de nuestro agente para pintarnos la interfaz gráfica del modo indicado en el CRM.

Ventana principal Unified Service Desk

Ventana principal Unified Service Desk

Con esto ya tenemos nuestro USD operativo tanto en nuestro PC como en nuestro CRM.