Receta para un Callout – Callouts (III)

Hoy, por fin J, retomamos el tutorial sobre callouts para Microsoft CRM 3.0. Podéis ver las anteriores entregas aquí (Primera parte y Segunda Parte). En esta nueva entrega vamos a ver que necesitamos para crear un pre-callout y un post-callout, y los pasos necesarios para desplegarlos en el servidor de Microsoft CRM.


Paso 1 – Preparar el entorno de desarrollo


Microsoft CRM 3.0 está construido sobre .Net Framework 1.1 lo que nos obliga, en principio, a utilizar Visual Studio .Net 2003 para desarrollar un callout. Digo en principio, porque existe una plantilla de proyecto para Visual Studio 2005 que nos permitirá crear un Callout en Visual Studio 2005, de la que ya hablamos una vez.


Lo primero que tendremos que hacer para desarrollar un Callout es copiar la dll con la clase base para los callouts a nuestro entorno de desarrollo para posteriormente incluirla en las referencias de nuestro proyecto en Visual Studio. Esta dll se encuentra en el cd de instalación de Microsoft CRM <server cd>binassemblyMicrosoft.Crm.Platform.Callout.Base.dll . Nota: No será necesario copiar esta dll al servidor cuando despleguemos el callout, ya que está en la GAC del servidor.


Una vez realizado esto ya podemos crear una nueva clase en el proyecto que será la que contenga el código para nuestro(s) Callout(s), hablo en plural porque en realidad la clase puede implementar varios callouts (de distinto tipo) ya que cada evento de callout es un método. Así por ejemplo en una sola clase podremos implementar un callout para loe eventos postcreate, precreate, postupdate y preupdate, u otra combinación que necesitemos.


En la nueva clase que hemos creado tendremos que añadir la referencia al espacio de nombre donde se encuentra la clase base de la que heredaremos para crear nuestro callout. En C# using Microsoft.Crm.Callout; . Y luego hacer que nuestra clase herede de CrmCalloutBase. Algo tal que así:


….
using Microsoft.Crm.Callout;

namespace CalloutSample2
{
class CalloutComponent: CrmCalloutBase
{
//….
}

}


Paso 2 – Desarrollar nuestro Callout


Bueno, ahora en nuestra flamante clase sólo tenemos que redefinir el método(s) que queramos utilizar, y gracias al IntelliSense de Visual Studio, bastará con empezar a escribir public override y podremos seleccionar el tipo de callout que necesitemos. En el sdk podéis encontrar todas las firmas de métodos disponibles para los callouts. Así por ejemplo un método para precreate podría ser el siguiente.


public override PreCalloutReturnValue PreCreate(
CalloutUserContext userContext,
CalloutEntityContext entityContext,
ref string entityXml,
ref string errorMessage
)
{
//Codigo del callout, por ejempo comprobar duplicados

return PreCalloutReturnValue.Continue;
}


Fijaros que los pre-callouts deben devolver un valor del tipo PreCalloutReturnValue para determinar cómo continua el proceso de ejecución: continue (continua el procesamiento de los demás callouts), stop (detiene el procesamiento de los callout y pasa directamente a ejecutar la operación de la plataforma) y abort (aborta la ejecución del resto de callouts y de la operación de la plataforma, al usuario se le mostrará el mensaje de error definido).


Y un método para un postcreate podría ser este otro.


public override void PostCreate(
CalloutUserContext userContext,
CalloutEntityContext entityContext,
String postImageEntityXml
)
{
WriteToFile(String.Format(“PostCreate called.n
postImage = {0}”
,postImageEntityXml));
}


Importante: En el desarrollo de un callout debemos evitar…



  • Provocar bucles infinitos: Si desde un callout hacemos alguna operación sobre Microsoft CRM que provoque la activación del mismo callout caeremos en bucle infinito. Por ejemplo: Desde un callout de postupdate de una entidad llamar a los servicios web para cambiar algún objeto de esa misma entidad provocará un bucle infinito de disparo de callouts.
  • Escribir por consola: El código de un callout no puede escribir en la consola Console.Write ni utilizar llamadas de interop Pinvoke.
  • Desperdiciar memoria: Debemos liberar todos los recursos que utilicemos en nuestro código.

Paso 3 – Desplegar el Callout


Lo primero será crear (o editar) el fichero callout.config.xml que tendrá que ser copiado al directorio <installdir>Program FilesMicrosoft CRMserverbinassemblycallout.config.xml. Este fichero tendrá una etiqueta raíz callout.config, dentro de ella tendremos las etiquetas callout que permiten indicar una entidad y un evento para el que registraremos métodos que manejarán el evento de callout. Por ejemplo:


<callout.config version=”1.0″>
<callout entity=”account” event=”PreCreate”>

</callout>
<callout entity=”account” event=”PreSetState”>
….
</callout>
<callout entity=”account” event=”PostCreate”>

</callout>
</callout.config>


Dentro de una definición de <callout> … </callout> insertaremos los tags de subscription para registrar todos aquellos métodos de callout que serán llamados en el momento de dispararse el evento. En el tag de subscription debemos de establecer, como mínimo, los atributos assembly y class; que indican respectivamente el nombre de la dll y el nombre de la clase (incluyendo namespaces) que contienen al método apropiado. Fijaos que no tenemos que indicar el nombre del método ya que el nombre es conocido (herencia de la clase base).


Además opcionalmente podemos indicar, mediante el atributo onerror, que hacer en caso de que el método genere una excepción, si ignorarlo (ignore) o abortar (abort); aunque esto es sólo para los post-callouts esta atributo es ignorado en los pre-callouts (tomando el valor por defecto ignore) ya que estos tienen la obligación de devolver un PreCalloutReturnValue en el que indicar la opción a tomar. Así mismo, tenemos la posibilidad de indicar, mediante el atributo timeout, un valor de timeout en segundos para la ejecución del método, por defecto 60 y como máximo 600.


<callout entity=”account” event=”PreSetState”>
</subscription assembly=”CalloutAssembly.dll” timeout=”100″
class=”MyCallouts.PreSetStateAccount”>
</callout>


Para un PreCallout la configuración termina aquí, pero para un post-callout podemos indicar un par de cosas más. Los pre-values (valores previos a la operación) y los post-values (valores de la entidad después de ejecutar la operación) que necesitamos. Se indican en mediante un tag que contiene el nombre de esquema de un atributos (uno a uno) o el comodín @all (todos), como podemos ver en el siguiente ejemplo. Nota: En los pre-callouts no es necesario esto ya que se le pasan todos los nuevos valores disponibles y si necesitasen consultar los valores actuales podrían utilizar los servicios web o vistas filtradas.


<callout entity=”appointment” event=”PostUpdate”>
<subscription assembly=”CalloutAssembly.dll”
class=”MyCallouts.PostCreateApt”>
<prevalue>subject</prevalue>
<postvalue>subject</postvalue>
</subscription>
</callout>
<callout entity=”invoice” event=”PostAssign”>
<subscription assembly=”CalloutAssembly.dll”
class=”MyCallouts.PostAssignInvoice”>
<prevalue>billto_country</prevalue>
<postvalue>billto_country</postvalue>
<prevalue>shipto_line2</prevalue>
<postvalue>shipto_line2</postvalue>
<prevalue>billto_city</prevalue>
<postvalue>billto_city</postvalue>
<prevalue>shipto_line1</prevalue>
<postvalue>shipto_line1</postvalue>
</subscription>
</callout>


Ahora que ya tenemos el fichero de configuración en el directorio indicado, sólo nos resta copiar la dll que contiene nuestro callout al mismo directorio (solo nuestra dll no hace falta la de la clase base de callout). Una vez hecho esto debemos reiniciar nuestro servicio de IIS (iisreset en una consola) y reiniciar el CRM workflow service y el CRM bulk e-mail service. Y listo, nuestros callouts estarán preparados para ejecutarse cuando se produzcan los eventos para los que los registramos.


En caso de que hubiese algún problema en el fichero de configuración, este se mostraría en el registro de eventos del sistema en el log de Aplicación, así que conviene darle un vistazo para ver si ha ocurrido algo.


En próximas entregas…


Seguiremos viendo más a fondo detalles de los callouts como: llamadas a los servicios web e impersonación, serialización y deserialización, depuración… y lo que propongáis.


Un saludo,


Marco


PD: Espero no tardar tanto en volver a escribir, está siendo un final de año de infarto con cantidad de trabajo, y si no escribo más a menudo no es por falta de ganas si no de tiempo… Ahora mismo en Plain Concepts estamos embarcados en varios proyectos muy interesantes y que seguro que darán para muchos post. Un día de estos le diré a mi amigo Rodrigo Corral que me explique su truco para poder escribir en cantidad y calidad 😉


 


 

5 comentarios en “Receta para un Callout – Callouts (III)”

  1. he seguido la receta, pero no veo resultados 🙁

    mi codigo es:

    using System;
    using System.Reflection;
    using System.IO;
    using System.Xml;
    using System.Xml.Serialization;

    using Microsoft.Crm.Callout;
    using Microsoft.Win32;

    namespace AsociarColaboradorActividad
    {
    ///

    /// Descripción breve de Class1.
    ///

    public class CalloutComponent: CrmCalloutBase
    {
    public CalloutComponent()
    {
    //
    // TODO: agregar aquí la lógica del constructor
    //
    }

    public override void PostCreate(
    CalloutUserContext userContext,
    CalloutEntityContext entityContext,
    String postImageEntityXml
    )
    {
    TextWriter log = TextWriter.Synchronized(
    File.AppendText(@”C:\Create.txt”));
    log.WriteLine(“PostCreate”);

    log.Close();

    }

    }
    }

    y el callout.config contiene:


    @all @all

  2. Hola Magy,
    Para estas cosas mejor utiliza los foros y no los comentarios.
    Lo más probable es que no te funcione por que el código del callout se ejecuta bajo los permisos de la cuenta de servicio de red (si has instalado por defecto el CRM), y esa cuenta del sistema no puede escribir en el directorio ráiz. Prueba a intentar escribir en el mismo directorio en el que se encuentra la dll del callout, o en el directorio temporal del sistema.

    Un saludo

  3. Hola Marco.
    Estaba trabajando bien con siguiendo todos estos pasos, pero tuve que cambiar de ambiente de desarrollo y ahora, al momento de recuperar información desde el evento no me trae ninguno de los atributos que le pido, siendo estos atributos siempre presentes como el id o el estado. El xml que me retorna es el siguiente:

    Y mi callOut.config.xml es muy corto y es:



    activityid statecode statecode

    Qué puedo estar pasando por alto o haciendo mal? Alguna idea?
    Gracias por su ayuda!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *