Trabalhando com DLLs externas em plugins ou atividades customizadas de workflow

by Pedro Azevedo 13. April 2016 08:38

Boas pessoal,

Hoje venho falar de um mecanismo que é o meu dia-a-dia no desenvolvimento de plugins ou atividades customizadas de workflow. Sempre que começamos um projeto vamos verificar que muito código pode ser reutilizado, ou seja, código que se repete em vários plugins por exemplo. Imaginem por exemplo um requisito que qualquer email temos que usar o mesmo utilizador, então em cada plugin teríamos que fazer o mesmo código.

A solução pode passar por colocar num projeto a parte e daí gerar uma DLL, assim podemos usar esse código nas atividades de workflow e em múltiplos projetos. O problema é que o CRM não deixa que coloquemos referências externas a DLLs, principalmente no CRM Online.

A solução passa por usarmos o ILMerge uma ferramenta gratuita e muito usada, onde o seu principal objetivo é fazer merge entre DLLs e gerar apenas uma. Assim a restrição de registar múltiplas DLLs fica ultrapassada, pois o plugin e a nossa biblioteca vão na mesma DLL. Antes a sua configuração ainda era complicada, mas a uns anos descobri este post que utiliza uma tarefa do MSBuild que permite otimizar muito o processo.

Presumindo que vocês já têm a vossa solution montada, vamos instalar o pacote NuGet chamado MSBuild.ILMerge.Task sobre o projeto do nosso plugin\atividade de workflow:

image

Depois de instalarmos este pacote NuGet, vamos adicionar a DLL da nossa biblioteca. Esta tarefa de MSBuild vai ter a função de fazer “merge”  de todas as DLLs que estejam na pasta bin do nosso plugin. Se forem a essa pasta vão visualizar mais DLLs e principalmente as quatro principais para desenvolvermos sobre o CRM:

image

Sobre estas referências temos que ir as propriedades dessas DLLs e mudar a configuração, “Copy Local” e colocamos a false. Assim essas DLLs não ficam no merge.

image

Antes de compilarmos podemos ver a estrutura atual da pasta bin:

image

Depois de um clean e se recompilarmos novamente o projeto passamos a ter apenas uma DLL:

image

Para confirmarmos que realmente as duas DLLs estão juntas, podemos recorrer a ferramenta ILSpy, que inspeciona a DLL:

image

Com isto podemos continuar com o registo da nossa DLL sem quaisquer problema.

 

Até a próxima.

Tags: , ,

Registar resposta de campanha numa oportunidade

by Pedro Azevedo 2. June 2015 11:55

Boas pessoal,

Mais uma vez aproveito este espaço para responder a uma pergunta do fórum do MSDN tem sido uma boa fonte de inspiração. Desta vez a pergunta era como poderíamos gravar a referência para a resposta de campanha quando a transformamos numa oportunidade, ou seja, quando convertemos uma resposta de campanha numa oportunidade, como podemos gravar a referência dessa resposta de campanha.

Foi algum que nunca tinha dado grande importância por isso fui ver qual era o comportamento por defeito e se o sistema já gravava por si só essa informação, pois não guarda a única coisa que guarda desta interação é a campanha onde está inserida esta resposta de campanha.

Próximo passo recorrer a um fluxo de trabalho, também não temos como obter esta informação quer na atualização da resposta de campanha, quer na criação da nova oportunidade. A abordagem a seguir foi tentar por Javascript apanhar a resposta da caixa de diálogo, aquando da conversão também sem sucesso. Depois fui para a documentação para ver se esta conversão estava assente em alguma mensagem, se assim fosse poderíamos registar nessa mensagem através de um plugin, tal como acontece quando por exemplo convertemos uma Lead num Oportunidade. Mais uma vez sem sucesso. Numa tentativa já desesperada (nem tanto foi mesmo para colocar algum drama Sorriso) fui ver o que a caixa de diálogo fazia por trás dos panos para tentar emular o comportamento através de uma caixa de diálogo personalizada, mas a coisa não se adivinha fácil por isso também deixei cair essa solução.

Eu poderia ter colocado logo a resposta correta mas penso que é bom sabermos as várias possibilidades que temos quando estamos a trabalhar com uma plataforma tão rica como esta, bom a solução que arranjei não é ideal pois baseia-se numa solução assíncrona e sem certezas que realmente vamos apanhar a resposta de campanha. Então a solução foi criar um plugin na mensagem de Create da Oportunidade. Daquilo que estive a estudar a primeira coisa que faço é saber se tem a referência a uma campanha, isto quer dizer que este Create poderá vir de uma conversão de resposta de campanha

public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity newOpportunity = (Entity)context.InputParameters["Target"];

if (newOpportunity.Contains("campaignid"))
{
// Obtain the organization service reference.
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

FilterExpression filter = new FilterExpression(LogicalOperator.And);

ConditionExpression condExprRegarding =
new ConditionExpression("regardingobjectid", ConditionOperator.Equal, ((EntityReference)newOpportunity["campaignid"]).Id);
ConditionExpression condExprSubject = new ConditionExpression("subject", ConditionOperator.Equal, newOpportunity["name"]);

filter.Conditions.Add(condExprRegarding);
filter.Conditions.Add(condExprSubject);

QueryExpression query = new QueryExpression("campaignresponse");
query.Criteria = filter;
query.ColumnSet = new ColumnSet(new string[] { "activityid" });

EntityCollection campaignResponse = service.RetrieveMultiple(query);
if (campaignResponse.Entities.Count == 1)
{
EntityReference entRef = new EntityReference("campaignresponse", (Guid)campaignResponse.Entities[0]["activityid"]);
newOpportunity["new_respostadecampanhaid"] = entRef;
}
else if (campaignResponse.Entities.Count <= 0)
{
//Erro
}
else
{
//Erro
}
}
}
}

Até a próxima.

Tags: , , ,

Como fazer debug de um plugin e atividade customizada no CRM On-Premise

by Pedro Azevedo 4. December 2014 02:23

Boas pessoal,

Vou continuar a série de fazer debug. Até agora abordamos como realizar debug sobre plugins online e em Web Resources. De referir que a prática que usamos no CRM Online pode-se usar no on-premise também.

Hoje quero falar sobre fazer debug em plugins num ambiente on-premise, que vai permitir realizar um debug em real-time. Para ser mais exato este procedimento é para código servidor, ou seja, tanto dá para plugins como para atividades workflow.

A primeira premissa é termos a nossa DLL do plugin ou da atividade de workflow e o ficheiro PDB (contém informações para realizar debug). Temos que colocar estes dois ficheiros na pasta: “<pasta de instalação>\Microsoft CRM\server\bin\assembly” (C:\Program Files\Microsoft CRM\server\bin\assembly), nesta pasta também devem ser todas as DLLs que se dependa a não ser que estas estejam registadas no GAC.

Uma vez que temos estes ficheiros podemos chegar ao nosso servidor de desenvolvimento e com o projeto do plugin aberto anexarmos um destes processos:

  • w3wp.exe para os plugins síncronos;
  • Microsoft.Crm.Application.Hoster.exe para quando temos uma ligação offline através do Outlook.
  • CrmAsyncService.exe quando se trata de um plugin assíncrono ou uma atividade workflow
  • Microsoft.Crm.Sandbox.WorkerProcess.exe quando temos o plugin registado no modo sandbox.

Vejam a seguir alguns screenshots de como fazer attach a alguns dos processos acima:

Com esta configuração o próximo plugin ou atividade de workflow irá parar no breakpoint definido.

As vezes pode ser frustrante porque o breakpoint não é ativado. Quando isto acontece podemos seguir uma espécie de checklist:

  1. Reset ao IIS (diretamente no IIS ou na linha de comandos escrever iisreset)
  2. Se for uma atividade de workflow ou plugin assíncrono, restaurar o serviço Assync do CRM
  3. Recompilar (em vez de Rebuild, podemos efetuar também o clean) o projeto do plugin ou atividade workflow
  4. Colocar a DLL e o PDB na pasta referida
  5. Registar o assembly pelo Registration Tool
  6. No Visual Studio colocar o breakpoint e anexar os processos referidos.

 

Se no Visual Studio se houver a seguinte mensagem sobre o breakpoint, quer dizer que temos que efetuar a lista acima:

Se o breakpoint apresentar a mensagem a seguir não se preocupem que em principio ele para no breakpoint:

E aqui está um exemplo, neste caso este plugin é lançado aquando da criação de um cliente:

Esta estratégia funciona bem nos ambientes de desenvolvimento, onde temos o visual studio instalado na mesma máquina onde está o servidor de CRM. Caso não tenhamos este cenário necessitamos de um auxiliar que é o Remote Debugger instalado. Podem ver aqui um bom artigo para auxiliar a sua instalação. Depois de estar instalado o Remote Debugger é colocarmos no campo Qualifier o nome do servidor.

 

PS: A versão do CRM usado neste post foi o CRM 2011 com o VS 2010, mas em outros ambientes é praticamente igual.

 

Até a próxima.

Tags: , , ,

Como fazer debug de um plugin no CRM Online

by Pedro Azevedo 11. June 2014 06:14

Boas pessoal,

Hoje vou mostrar como podemos efectuar debug num plugin do CRM Online, como vão ver não é um debug em real time mas mesmo assim permite-nos ver como é que os dados fluem no nosso plugin. Basicamente é capturado todos os dados num ficheiro e vamos carregar esse ficheiro na ferramenta “Plugin Registration”. Vou já mostrar com a nova interface da ferramenta que apareceu com o SP1 do Microsoft Dynamics CRM Online. É bom relembrar que apenas temos esta opção devido ao facto de a única maneira que temos para fazer deploy dos plugins é no modo sandbox.

Tendo em conta que já temos um plugin registado e queremos realizar o debug deste plugin através da ferramenta “Plugin Registration”. Esta ferramenta está na instalação do SDK, para ter acesso a nova interface relembro que têm que fazer no mínimo o download do SDK do SP1. Depois de instalar tem acesso aplicação nesta pasta …\SDK\Tools\PluginRegistration\PluginRegistration.exe.

Depois de iniciar aplicação terá este aspecto:

 Aqui carregamos no botão “CREATE NEW CONNECTION”, depois disto teremos que introduzir as nossas credenciais:

 

Depois da autenticação é listado a lista de Plugins registados e seleccionamos o plugin sobre o qual queremos realizar o debug e carregamos em “Install Profile”:

 

Depois do profile instalado irá aparecer um nó com o “Plugin-in Profiler”, sobre o passo registado dizemos que queremos começar o profile, carregando no botão “Start Profiling”:

 

Vai aparecer uma janela de settings que podemos aceitar os por defeito:

 

O nó do passo altera-se como vamos ver mais adiante, agora vamos até a nossa instância de CRM Online e vamos despoletar o nosso plugin, ao correr vai aparecer uma janela com o título “Erro de Processo de Negócio” onde vamos fazer download do ficheiro:

De seguida vamos ao nosso Visual Studio e vamos fazer “attach” ao processo da ferramenta “Plugin Registration”:

 

E colocamos um breakpoint onde vamos querer parar e fazer debug. Voltando a ferramenta e voltando ao passo do plugin, verificamos que o passo está marcado como “Profiled”, e seleccionamos o “Debug”:

 

Na janela a seguir vamos então seleccionar o ficheiro que fizemos download anteriormente e colocamos no campo: “Profile Location” e vamos também dizer onde está a DLL respeitante ao nosso plugin, depois de carregar o plugin temos a opção de escolhermos a classe responsável pelo plugin. Ao seleccionarmos o botão “Start Execution” ele vai correr o plugin com base no ficheiro de profile que disponibilizamos e podemos fazer step by step com os dados que inserimos:

 

 

 Assim vimos como podemos realizar debug de um plugin no CRM Online. Não é o ideal mas dá uma tremenda ajuda.

 

Até a próxima.

Tags: , , , , ,

Plugin para intervir na operações especiais - Ganho e Perda da Oportunidade

by Pedro Azevedo 18. May 2014 19:21

Boas pessoal,

Na continuação deste post vou aqui relatar como realizar o dito plugin, um plugin que interfere em operações especiais. Neste caso vai-se referenciar as operações na entidade Oportunidade que permite marcar um registo como Ganho ou Perdido. Imaginamos que se quer verificar se um determinado campo está preenchido, neste caso quero obrigar que o utilizador preencha a descrição antes de fechar a oportunidade.

O código é o seguinte:

public class CloseOpportunity : IPlugin {
	public void Execute(IServiceProvider serviceProvider) {
		ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
		IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

		if (context.InputParameters.Contains("OpportunityClose") && context.InputParameters["OpportunityClose"] is Entity) {
			Guid oppId = ((EntityReference)((Entity)context.InputParameters["OpportunityClose"]).Attributes["opportunityid"]).Id;

			IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
			IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

			Entity opportunity = service.Retrieve("opportunity", oppId, new Xrm.Sdk.Query.ColumnSet(true));
			if (!opportunity.Contains("description") || string.IsNullOrEmpty(opportunity["description"].ToString()))
				throw new InvalidPluginExecutionException("Para fechar a Oportunidade terá que preencher a descrição");
		}
	}
}

O normal em plugins é esperarmos a entidade no parâmetro “Target” neste caso, esta informação está no parâmetro “OpportunityClose”, ou seja, vem na forma do objecto final, pois quando fechamos uma Oportunidade temos que preencher informações, do estado, receita real, data de fecho e caso seja perdida qual o concorrente que ganhou.

Para verificarmos as propriedades da Oportunidade teremos que obter e no objecto “OpportunityClose” tem o ID da Oportunidade e é com esse ID que vamos obter a Oportunidade relacionada.

No código ainda se pode ressalvar como cancelamos a operação, com recurso a excepção “InvalidPluginExecutionException”, a mensagem que colocamos na excepção é a mensagem que vai aparecer ao utilizador.

Depois do código completo temos que registar o plugin com as seguintes configurações:

  •         Mensagem: Win ou Lose
  •         Entidade Primária: Opportunity
  •         Entidade Secundária: Nenhuma

E registamos no event Pre-Operation para que não seja gravado na BD.

Vamos ver diretamente no Plugin Registration como fica, depois de realizarmos uma ligação, podemos registar o nosso assembly:

 Após selecionarmos a opção "Register New Assembly" aparecerá um formulário para colocarmos o caminho do assembly que contém o nosso plugin e escolhemos qual o Plugin que queremos registar, neste caso estou a selecionar o Plugin acima:

 Se tudo correr bem obtém-se a seguinte mensagem:

Irá aparecer um novo nó com o assembly que se acabou de criar e sobre este vamos adicionar um "passo" (Register New Step):

No formulário a seguir configuramos em que mensagem queremos nos registar, qual a entidade primária, em que fase do pipeline e o modo de execução:

Com isto temos o nosso Plugin registado e pronto a funcionar.

Até a próxima.

Tags: , , , ,

About

Muito bem casado, Pai babado e um gosto muito grande pela tecnologia.

Tenho um lema "Sharing is Learning"

Mais aqui -> http://www.psazevedo.com

Month List