8/2/10

¿Qué versión de UR tengo?

Aquí he copiado una lista de bite my bytes con las versiones de Update Rollups de CRM asociadas a los números de versión de las DLLs. Es algo que tengo que hacer a menudo cuando me encuentro con una instalación de CRM que no he instalado (o he instalado y olvidado luego…) ¿qué versión del Update Rollup tengo instalada?

Versión Build Number Fecha
RTM 4.0.7333.3 19/12/2007
Rollup 1 4.0.7333.1113 24/11/2008
Rollup 2 4.0.7333.1312
4.0.7333.1316
15/01/2009
08/02/2009
Rollup 3 4.0.7333.1408 12/03/2009
Rollup 4 4.0.7333.1551 07/05/2009
Rollup 5 4.0.7333.1644
4.0.7333.1645
02/07/2009
Rollup 6 4.0.7333.1750 27/09/2009
Rollup 7 4.0.7333.2138 22/10/2009
Rollup 8 4.0.7333.2542 17/12/2009
Rollup 9 4.0.7333.2644 11/02/2010
Rollup 10 4.0.7333.2741 04/08/2010
Rollup 11 4.0.7333.2861 03/06/2010
Rollup 12 4.0.7333.2935 02/08/2010
Rollup 13 4.0.7333.3018 23/09/2010

Se trata de mirar cualquier dll de la carpeta C:\Program Files\Microsoft Dynamics CRM\Server\bin y mirar su número de build. Para esto lo más sencillo es hacer botón derecho - Propiedades. También se puede añadir la columna File Version al explorador de ficheros.

1/2/10

MSMQ Custom Workflow Activity

En cualquier proyecto de CRM que se precie tiene que haber algo de integración, ¿no? Pues lo que me cuelgo aquí es un ladrillo para la integración. También es un ladrillo de post, por cierto. La idea es permitir que, desde el Workflow estándar, un usuario poderoso (power user) sea capaz de enviar una entidad de CRM a una cola de MSMQ en respuesta a algún evento de CRM. Puede que sea una idea disparatada, no lo sé, pero permite flexibilidad, es básica y se explica en un párrafo.




using System;
using System.Messaging;
using System.Web.Services.Protocols;
using System.Workflow.ComponentModel;
using System.Workflow.Activities;
// Microsoft Dynamics CRM namespaces
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Workflow.Activities;

namespace CrmADiario.Crm.Workflow
{

public class SendToQueueBase : SequenceActivity
{

public static void SendEntityToQueue(
ActivityExecutionContext ctx,
string queueAddress,
Type activityType,
string entityName,
Guid entityId)
{
try
{
var crmContext =
(IContextService)ctx.GetService(typeof(IContextService));
var crmService =
crmContext.Context.CreateCrmService();

var resp = (RetrieveResponse)crmService.Execute(
new RetrieveRequest
{
Target = new TargetRetrieveDynamic
{
EntityId = entityId,
EntityName = entityName
},
ReturnDynamicEntities = true,
ColumnSet = new AllColumns()
});

var message = new Message(resp.BusinessEntity);
var q = new MessageQueue(queueAddress);
q.Send(message, activityType.ToString());
}
catch (SoapException soapEx)
{
var errorMessage = String.Format(
"A CRM error occurred executing {0} in queue {1}\r\n{2}",
activityType,
queueAddress,
soapEx.Detail.OuterXml);
throw new StopWorkflowException(WorkflowCompletionStatus.Failed, 1024, errorMessage);
}
catch (Exception ex)
{
var errorMessage = String.Format(
"An error occurred executing {0} in queue {1}\r\n{2}",
activityType,
queueAddress,
ex.Message);
throw new StopWorkflowException(WorkflowCompletionStatus.Failed, 1024, errorMessage);
}


}
}
}



La clase base SendToQueueBase contiene la funcionalidad de ejecución de la actividad en el método SendToQueue que es usado desde los métodos Execute de las subclases. Por cierto, no he sido capaz de fabricar una sola clase que haga el trabajo así que he tenido que fabricar (copiar y pegar, vamos) tantas clases de actividad como entidades de CRM se quieran enviar a MSMQ.




using System;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Workflow;

namespace CrmADiario.Crm.Workflow
{
[CrmWorkflowActivity("Send contact to queue", "MSMQ Utilities")]
public class SendContactToQueue : SendToQueueBase
{

public static readonly DependencyProperty ContactProperty =
DependencyProperty.Register("Contact", typeof(Lookup), typeof(SendContactToQueue));

public static DependencyProperty QueueAddressProperty =
DependencyProperty.Register("QueueAddress", typeof(String), typeof(SendContactToQueue));

[CrmInput("Queue address")]
public String QueueAddress
{
get { return (String)GetValue(QueueAddressProperty); }
set { SetValue(QueueAddressProperty, value); }
}

[CrmReferenceTarget("contact")]
[CrmInput("Contact")]
public Lookup Contact
{
get { return (Lookup)GetValue(ContactProperty); }
set { SetValue(ContactProperty, value); }
}

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
SendEntityToQueue(executionContext, QueueAddress, GetType(), "contact", Contact.Value);
return base.Execute(executionContext);
}
}
}


Esta clase derivada envía un contacto serializado como una DynamicEntity a la cola de MSMQ que se indique. Y para el resto de entidades, copiar, pegar y cambiar donde dice "contact" por el nombre de la entidad que sea. No es muy elegante, pero es hasta donde he llegado. Si a alguien se le ocurre cómo generalizar esto un poco, ¡adelante!