Olá pessoal,
No post anterior, escrevi como realizar a comunicação com o serviço WCF externo do Dynamics 365 no server side (utilizei um plugin).
Neste post, irei fazer a mesma chamada, porém utilizando o que acredito que seja o mais recomendado e eficiente. Usar Biding HTML e o Contrato do serviço.
É imprescindível que o serviço WCF do post anterior esteja implementado. Pois, ele será a base para este. Na verdade, a única coisa que este post apresenta de diferente é o meio/forma de comunicação com o serviço!
Primeiramente, precisamos gerar o contrato do WCF, para isso, basta navegar no browser pelo endereço do serviço que veremos um tela similar a esta:
Veja que podemos criar nosso contrato utilizando o svcutil.exe (quando instalamos o Visual Studio ele é automaticamente instalado). O svcutil irá ler a interface do WCF e gerar nosso contrato.
Eu inseri alguns parâmetros para facilitar o uso do contrato:
svcutil.exe http://tiagowin20163976.cloudapp.net/WcfService/Mat.svc?wsdl ^ /namespace:*,"Dynamics365" ^ /d:"C:\Users\tiago.cardoso\Downloads"
Para executar o svcutil, precisamos abrir o Developer Command Prompt for VS (cada versão do VS tem programa) e colar o script acima:
No meu caso o arquivo Mat.cs será adicionado na pasta Downloads. Copie e adicione no MESMO PROJETO ONDE O PLUGIN IRÁ FICAR!
A última parte não poderia ser diferente de criar o plugin propriamente! Vou seguir a mesma ideia do post anterior e criar para a entidade Conta (account). Foi colocar o código e depois irei comentar:
using Dynamics365; using Microsoft.Xrm.Sdk; using System; using System.ServiceModel; namespace Plugins { public class AccountCreate : IPlugin { #region Secure/Unsecure Configuration Setup private string _secureConfig = null; private string _unsecureConfig = null; public AccountCreate(string unsecureConfig, string secureConfig) { _secureConfig = secureConfig; _unsecureConfig = unsecureConfig; } #endregion public void Execute(IServiceProvider serviceProvider) { // Extract the tracing service for use in debugging sandboxed plug - ins. // If you are not registering the plug-in in the sandbox, then you do // not have to add any tracing service related code. ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); // Obtain the execution context from the service provider. IPluginExecutionContext context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext)); // The InputParameters collection contains all the data passed in the message request. if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity) { // Obtain the target entity from the input parameters. Entity entity = (Entity)context.InputParameters["Target"]; // Verify that the target entity represents an entity type you are expecting. // For example, an account. If not, the plug-in was not registered correctly. if (entity.LogicalName != "account") return; // Obtain the organization service reference which you will need for // web service calls. IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); try { // Plug-in business logic goes here. var serviceURL = "http://tiagowin20163976.cloudapp.net/WcfService/Mat.svc"; tracingService.Trace("- CallServiceByWebClientSOAP"); tracingService.Trace("Somar('4','5')"); // Create Bind object BasicHttpBinding myBinding = new BasicHttpBinding(); myBinding.Security.Mode = BasicHttpSecurityMode.None; myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; myBinding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None; myBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; // Create endpoint EndpointAddress endPointAddress = new EndpointAddress(serviceURL); // Create Channel to access Encrypt Service Interface ChannelFactory<IMat> factory = new ChannelFactory<IMat>(myBinding, endPointAddress); IMat channel = factory.CreateChannel(); // Call Encrypt Service var response = channel.Somar("4", "5"); tracingService.Trace("Result: " + response); // Close factory factory.Close(); } catch (FaultException<OrganizationServiceFault> ex) { throw new InvalidPluginExecutionException("An error occurred in MyPlug-in.", ex); } catch (Exception ex) { tracingService.Trace("MyPlugin: {0}", ex.ToString()); throw; } } } } }
Vamos lá:
- A primeira linha faz uma referência (namespace) ao contrato que criamos com o svcutil;
- O que acontence dentro do “try“:
- serviceUrl – Informamos a URL do serviço que estamos requisitando
- BasicHttpBinding – Criamos o binding que propriamente faz a conexão com o serviço WCF. Note que não estou utilizando nenhum método de autenticação ou proxy neste exemplo;
- endPointAddress – Criamos um objeto com o endpoint do serviço;
- factory – Informamos o contrato e endpoint para a classe ChannelFactory. Veja a conversão (unboxing) para o tipo do nosso contrato IMat;
- channel – Cria o canal com o endpoint, ou seja, cria/abre a conexão com o serviço;
- channel.Somar – Por fim, chamamos o método do serviço. Veja que por usarmos o contrato do serviço o método e parâmetros são reconhecidos! (tipados)
A resposta da chamada, nada mais é do que o que método retorna. Neste exemplo será um número! O número 9 (5+4)!
Assim, ao criar uma conta no CRM, quando observamos o log de execução do plugin, vemos:
Bom, é isso! Acredito que esta forma seja bem mais robusta e utilize melhores práticas de programação bem como funcionalidades mais atuais!
[]’s,
Tiago