Cómo Llamar a un Servicio WebAPI de .Net desde Salesforce

En un artículo anterior, Llamada a un Servicio Web WCF de .Net desde Salesforce, expliqué cómo realizar llamadas externas desde un desencadenador (trigger) en Salesforce para obtener datos de un servicio WCF creado en .Net. Esta solución estaba basada en SOAP como el protocolo de mensajes entre Salesforce y nuestro servicio web. Todos conocemos las ventajas y desventajas de SOAP comparado con REST, y lo que si es cierto es que REST es la opción preferida a la hora de crear servicios web. Así que en este artículo voy a modificar el ejemplo presentado en el artículo anterior y voy a usar REST en vez de SOAP.

Permitidme refrescar el problema que estamos tratando de resolver: nuestro cliente quiere crear presupuestos de ventas en Salesforce, pero quiere que el precio de los productos venga del ERP. Nuestra solución fue la de crear un servicio web de WCF (basado en SOAP) con .Net el cual, dado un identificador de producto, retornaba el precio de dicho producto. Luego hacíamos una llamada externa a éste servicio desde un desencadenador definido en el objeto QuoteLineItem en Salesforce. Mantendremos la misma arquitectura para la solución (el desencadenador y el servicio web) pero esta vez usaremos REST. Sugiero que leáis el artículo anterior para tener una mejor comprensión de lo que queremos hacer.

El Servicio WebAPI

Comencemos creando el servicio REST. Vamos usar Visual Studio para crear un proyecto de MVC WebAPI para esto. Usaremos Visual Studio Community Edition para crear el proyecto. Abre Visual Studio y crea un nuevo proyecto del tipo “ASP.Net Web Application” y llámalo ErpApiService. Selecciona “Web API” como plantilla y asegúrate de seleccionar “No Authentication” desde el botón de “Change Authentication” (para simplificar las cosas no nos meteremos con seguridad en este artículo).

change authentication salesforce crmservicio-web-api-salesforce-crm

Visual Studio creará un proyecto de ejemplo de Web API con un controlador de ejemplo. Dirígete a la carpeta de Controllers y renombra el archivo ValuesController.cs a ProductController.cs. Si Visual Studio pregunta si quieres aplicar el renombrado a todas las referencias en el código dile que sí. Reemplaza el contenido del archivo ProductController.cs con lo siguiente:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ErpApiService.Controllers
{
    public class ProductController : ApiController
    {
        // GET api/product/getPriceForCustomer?id={id}
        public decimal GetPriceForCustomer(string id)
        {
            try
            {
                ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings["ERP"];
                using (SqlConnection cn = new SqlConnection(connectionString.ConnectionString))
                {
                    using (SqlCommand command = new SqlCommand("salesforce_getProductPrice", cn))
                    {
                        command.CommandType = CommandType.StoredProcedure;

                        command.Parameters.Add("@productId", SqlDbType.VarChar).Value = (object)id ?? DBNull.Value;
                        SqlParameter priceParameter = command.Parameters.Add("@price", SqlDbType.Money);
                        priceParameter.Direction = ParameterDirection.Output;

                        cn.Open();
                        command.ExecuteNonQuery();

                        return (decimal)command.Parameters["@price"].Value;
                    }
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.Message);
                return 0;
            }
        }
    }
}

 

La línea resaltada es la línea más importante en este ejemplo, ya que define la firma de nuestro recurso REST. Por convención, si un método comienza con “Get” (como en nuestro ejemplo) el motor de WebAPI usará el método HTTP GET para realizar la llamada. El resto del código es código estándar de ADO.Net para realizar llamadas a un procedimiento almacenado (en este caso a una base de datos en SQLServer).

Hay que publicar este servicio web y obtener un URL público en internet. En mi caso lo he publicado en un servidor IIS en la DMZ y el URL es el siguiente: http://www.grupolanka.com/Salesforce/ErpApiService/api/Product?id={id} (no intentes probarlo ya que no funcionará). Ya estaríamos listos para consumir este servicio REST desde Salesforce.

Llamada al Servicio REST desde Salesforce

En Salesforce abre la consola de desarrollo y vamos a introducir un código anónimo para probar nuestro servicio. Introduce el siguiente código APEX:

String url = 'http://www.grupolanka.com/Salesforce/ErpApiService/api/Product?id=PADAP20001';

Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(url);
req.setMethod('GET');
HttpResponse res = h.send(req);

system.debug('Price: ' + res.getBody());

Deberías poder ver el precio enviado por el ERP en el log.

A continuación, vamos a cambiar la clase que teníamos de nuestro artículo anterior para reemplazar la llamada SOAP por la llamada a REST. En la consola de desarrollador, abre la clase QuoteLineItemProcesses y reemplaza el código con lo siguiente:

global with sharing class QuoteLineItemProcesses {
    @future (callout = true)
    public static void updateLinePrice(List<Id> lineItemIds) {
        Boolean changed = false;

        QuoteLineItem[] lineItems = [select QuoteId,Product2Id,UnitPrice from QuoteLineItem where Id in :lineItemIds];
        for(QuoteLineItem lineItem : lineItems) {
            Quote quote = [select q.AccountId from Quote q where Id = :lineItem.QuoteId];
            Product2 product = [select External_Id__c from Product2 where Id = :lineItem.Product2Id];

            String productCode = product.External_Id__c;    

            Decimal price = GetPrice(productCode);

            if(price > 0)
            {
                lineItem.UnitPrice = price;
                changed = true;
            }
        }

        if(changed) update lineItems;
    }

    private static Decimal GetPrice(String productCode) {
        String url = 'http://www.grupolanka.com/Salesforce/ErpApiService/api/Product?id=' + productCode;

        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(url);
        req.setMethod('GET');
        HttpResponse res = h.send(req);

        return Decimal.valueOf(res.getBody());
    }
}

La llamada al servicio REST desde un desencadenador sigue los mismos principios que mencionamos en el artículo anterior: necesita ser llamada desde una clase marcada con el atributo @future (para que la llamada sea asíncrona), necesita ser un método static void, y el desencadenador necesita ser del tipo after insert.

Ahora puedes probar la llamada al servicio agregando una nueva línea de producto a un presupuesto existente, Salesforce debería llamar al servicio REST y asignarle el precio del producto obtenido del ERP a la línea del presupuesto.

 

La versión original de este articulo ha sido publicada en http://www.giovannimodica.com/

Grupo Lanka es partner certificado para Salesforce España.