0 Comments

(Puedes ver este artículo en español aquí)

In a previous article, Call a .Net WCF Service from Salesforce, I explained how to make an external call in a Salesforce trigger to get data from a third party system by using a custom web service created in .Net WCF. This approach was using SOAP as the messaging protocol between Salesforce and our web service. We all know the advantages and disadvantages of SOAP compared to REST, but the truth is that REST is the preferred choice when it comes to creating web services. So, in this article I will modify the example presented in the previous post to use REST instead.

Allow me to refresh the problem we were trying to solve: our client wants to create sales quotes in Salesforce, but wants the price of products to come from the ERP. Our solution was to create a web service (a SOAP web service) in .Net WCF that given a product identifier returned the price of the product, we then called this service from a trigger defined in the QuoteLineItem object in Salesforce. We will keep the same architecture to the solution (the trigger and the web service) but this time we will use REST. I suggest you read the previous article to get a better understanding of what we would like to accomplish.

The WebAPI Service

Let’s start by creating our REST service. We will use an MVC WebAPI project in Visual Studio for this. I will use Visual Studio Community Edition to do this. Open Visual Studio and create a new “ASP.Net Web Application” name ErpApiService. Select “Web API” as the template and make sure you select “No Authentication” from the “Change Authentication” button (for simplicity we will not deal with security in this article).

New Asp.Net projectNew Web API project

Visual Studio will create a sample Web API project with a sample controller. Go to the Controllers folder and rename the file ValuesController.cs to ProductController.cs. If Visual Studio asks you to apply the rename to all references in code select yes. Replace the contents of the ProductController.cs file with the following:

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;
            }
        }
    }
}

The highlighted line is the most important in this example, it defines the signature of the REST resource. By convention, if a method starts with Get (as in our example) the WebAPI engine will use the HTTP GET method to call it. The rest of the code is just ADO.Net boilerplate code to call a stored procedure in a database (in this case a SQLServer database).

Publish this web service to a public URL. In my case I published it to an IIS server in the DMZ and the URL is the following: http://www.grupolanka.com/Salesforce/ErpApiService/api/Product?id={id} (don’t try it, it won’t work). Now, we are ready to consume this REST service from Salesforce.

Calling the REST Service from Salesforce

Go to Salesforce and using the Developer Console let’s create an anonymous code to test our service. Type the following APEX code:

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());

You should be able to see the price sent from the ERP in the log.

Now let’s change the class we had from our previous article to do the REST call instead of SOAP. On the Developer Console, open the class QuoteLineItemProcesses class and replace the code with the following:

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());
    }
}

The callout to a REST service from a trigger follows the same principles we outlined in our previous article: it needs to be called from a class marked with the @future tag (for asynchronous call), it needs to be a static void method, and the trigger needs to be a after insert trigger.

You can now test the call by adding a new line item to an existing quote, Salesforce should call the REST service and assign the product price from the ERP to the line item.

You can get the sample code from here: