Calling External Web Services from Salesforce.com – Part III: Building an Apex class that calls your web service

Part I: Hosting your web service
Part II: Opening your web service to the internet
Part III: Building an Apex class that calls your web service

In Part I & Part II of this series, I discussed the details of hosting a web service on your computer and exposing it to the internet. If you are working in an enterprise/corporate network environment, your web service is almost always not exposed to the internet. If so, I would encourage you to also read Part I & II of this series, so you get a basic idea on how to expose your web service so that Salesforce can connect to it. In this part, we will do the fun stuff – building an Apex class that can call this web service. Before we proceed, let us revise what happens when Salesforce calls our web service -

image

1 – Our custom Apex class hosted on the Salesforce.com platform makes an outbound web service call.
2 – The call reaches our modem that forwards it to the wireless router.
3 – Since port forwarding is turned on, the router then forwards the request to our computer’s IP Address.
4 - The computer’s firewall intercepts the request, and since we opened port 80 on the firewall, lets it pass through.
5 – The IIS on the computer receives the web service request, and services it.

Now that we have the basics cleared off, let’s get into the specifics – here are step-by-step instructions on building an Apex class that calls your web service :-

  • First, we need to get the WSDL file for our web service. The WSDL(Web service definition language) file is an XML-based representation of our web service – what methods it contains, data types of method parameters, return types, and the communication protocol related details.
  • To get the WSDL, simply open a browser and navigate to your web service, passing in ?wsdl as a query string parameter. For my web service, I navigated to http://localhost/MyWebService/Service1.asmx?wsdl (if you haven’t yet hosted the web service on your computer, read Part I of this article series.
  • If your web service is hosted correctly, you should see a block of XML in your browser window. Save this as a file with .wsdl extension.
  • Next, log into Salesforce.com, and go to Setup->Develop->Apex Classes. A list of classes shows up. Here, click on the “Generate from WSDL” button.

image

image

  • On the next screen, click the “Choose File” button, and select the WSDL file you had saved previously. Click the “Parse WSDL” button to check the validity of the WSDL file.
  • Did you get an error saying “Error: Failed to parse wsdl: Found more than one wsdl:binding. WSDL with multiple binding not supported” ? Well, that happens because the WSDL file generated for an Asp.Net web service has multiple bindings.
  • Let me get into a little more detail – if you open and inspect the WSDL file, you will see a <wsdl:binding> element. The binding element defines how to use the web service with a particular protocol (e.g. http), the XML encoding, the name of the operation, input/output parameters etc. For some reason, an asp.net web service WSDL file has multiple nodes for bindings. I don’t know why it does that – both nodes appear the same to me, so I don’t see the point of repeating the same information twice. Anyway, this confuses Salesforce.com when we try to import the WSDL to create an Apex class.

image

image

  • So, we do what any good software engineer would do – remove the extra binding and proceed :). So go ahead, delete the second <wsdl:binding> node. Also remove the corresponding <wsdl:port> node that was using this binding. Try parsing the file again in Salesforce.com – this should go through without errors. When it asked for Apex class name, I used “MyWebServiceApex”.
  • Navigate to the Apex class (MyWebServiceApex), and check out the code. Specially note my notes about using the correct IP Address – I cannot stress this enough. By default, Salesforce.com uses http://localhost as the address for the web service – you need to edit that in the class to make sure it is connecting to your web service.

image 

Adding a Remote Endpoint

  • Before we run the code to call our web service, we also need to let Salesforce know that this web service could be trusted. For this, we define a “Remote Site” – go to Setup->Administration setup->Security Controls->Remote Site Settings.
  • Enter your web service address etc. here, and give it a unique name.

image

  • Now you can start testing your web service.

Testing our class via Anonymous blocks

  • Next, we will test the class we just created – launch the developer console (Setup->Developer console). Locate the “Execute” text block at the top – this is where we can put our anonymous code block.

image

  • Copy-Paste the below code into the anonymous code block -
Code Snippet
  1. MyWebServiceApex.Service1Soap s1 = new MyWebServiceApex.Service1Soap();
  2. String result;
  3. result = s1.HelloWorld();
  4. System.Debug(result);
  • When you execute the code, make sure to check the “Open Log” checkbox. This will launch your execution log file as soon as your anonymous block is executed. The piece of code here basically reaches out to the web service hosted on your computer, and invokes the “HelloWorld()” web method.

image

  • Verify the log file, and you should see the output of your “System.Debug” statement in the logs :-

image

So, these were the steps you can follow to invoke your web service from Salesforce.com. This approach has various applications – you could build an “event” mechanism so that external systems are alerted whenever something happens in Salesforce.com. Or, you could build an external logging facility that logs each and every page visit to an external database. We will explore some of the additional complexities of this process in the next post.

16 comments:

  1. Hi Sourabh

    The tutorial is great, one clarification - does the PC need to expose a public IP

    regards
    harish

    ReplyDelete
  2. Hey i execute this code but its not working..

    Pls enter valid code.....

    ReplyDelete
  3. @Anonymous - I actually faced the same problem - how do I expose my web service on the Internet so Salesforce can call it ? -- I would recommend you read Part II of this series (http://writeforce.blogspot.com/2013/02/calling-external-web-services-from_8.html). This talks about how you can expose your web service to the internet from your home computer setup.

    ReplyDelete
  4. @Aravinth - Can you let me know which specific part is not working ? Couple of things I can think of - maybe your web service is not callable from the internet because you are behind a firewall ? Please read Part II of this series at http://writeforce.blogspot.com/2013/02/calling-external-web-services-from_8.html to understand how to host your web service so Salesforce can call it. The other thing is - in your apex class, did you make sure it is making the call to your machine ? Usually it will say http://localhost by default, which is wrong, because localhost means nothing for salesforce. You need to put your IP Address/hostname so that the address looks something like http://76.56.98.45/mywebservice/service1.asmx, based on your IP Address.

    ReplyDelete
  5. @saurabh : I call the functions in the console applications but it gives a error as following URL is not called out.. i changed my URL as u said , but even then i'm getting error, pls Give Brief explain idea about URL...


    Thanks & Regards
    Viswa(Aravinth Frnd)

    ReplyDelete
  6. Hi saurabh,
    Nice POst... Thanx a lot... Bt im getting error during execution called "Read Timed out"... after that i set timeout value for that... bt it shows the same error... pls reply me...

    thanks
    Arthu

    ReplyDelete
  7. Nice and Informative Post

    ReplyDelete
  8. @Viswa Raj - the URL is basically the URL where your web service is hosted. If you are working in a corporate environment, you are most likely behind a firewall - in this case, all calls to your web service will be blocked by the firewall. You need to talk to your network admin on opening up the firewall so that Salesforce can call your web service.
    If you want to test whether your web service is callable from outside, go to http://www.webpagetest.org/, and put your web service's URL in the test URL box. This will then try to hit your web service, and will display the appropriate error page if the web service is not callable.

    ReplyDelete
  9. I did all the setup but getting 'Failed to connect ' status. I made changes to firewall and port forwarding on my personal router too.

    ReplyDelete
  10. Getting navigation error when testing the web service on webpagetest site

    ReplyDelete
  11. I feel there is something wrong with you setup - you should definitely be able to hit http://www.webpagetest.org/

    Are your working on an internal network ? The other thing I can think of is that your ISP has blocked this website ? Not sure, can you give some more information about your network setup.

    ReplyDelete
  12. Hi,

    I am new to Salesforce.I have gone through this blog and found some interesting stuff about SF.

    I am trying to call our application soap api's from Salesforce. I did parsing the my wsdl in salesforce system. Basically the wsdl requires the authentication. When I tried to invoke api from Salesforce Apex code, I could see the authentication. Could you please explain how to pass credentials while parsing the wsdl and generate the apex class or help me out how to handle the other system soap API credentials.

    Thanks in advance...

    ReplyDelete
  13. i have error like Method does not exist or incorrect signature: [MyWebServiceApex.TempConvertSoap].CelsiusToFahrenheit() method not how toresolve it.......???

    ReplyDelete
  14. got the exact same message:
    line 6, column 10: Method does not exist or incorrect signature: [MM01ValidateOnly.ServiceSoap].RunWithSAPCreds()
    If we need to put a userId and password to access this site, where can we put it?

    ReplyDelete
  15. Saurabh--- please help me out how we can call salesforce webservice method through html page not vf pages.. I know in vf pages we can use JavaScript to call web service method.. but in standalone html page is it possible.

    our requirement ---> through html page we hv to save inser/update in salesforce. Please help!!!!!!!!

    ReplyDelete
  16. Pretty great post. I simply stumbled upon your blog and wanted to say that I have truly enjoyed browsing your blog
    posts. In any case I'll be subscribing on your rss feed and
    I hope you write again very soon!

    My blog post; Dirk Craen

    ReplyDelete