Orchestrating the Cloud: Part II – Creating and Consuming a Salesforce.com Service From BizTalk Server

In my previous post, I explained my cloud orchestration scenario where my on-premises ESB coordinated calls to the Google App Engine, Salesforce.com and a local service, and returned a single data entity to a caller.  That post looked at creating and consuming a Google App Engine service from BizTalk.

In this post, I’ll show you how to customize a data object in Force.com, expose that object via a web service, and invoke that from BizTalk Server.  As a ridiculously short primer, SalesForce.com is considered the premier SaaS CRM product which provides sales force automation and customer service modules serving both large and small organizations alike.  Underlying SalesForce.com is a scalable robust platform (Force.com) which can be used to build all sorts of data-driven applications. You can leverage the apps built by others through the AppExchange which lists a diverse range of applications built on Force.com.

Ok, enough of a sales job.  First off, I signed up for a free Force.com account.  I’m going to extend the out-of-the-box “Contact” object by adding a few new fields.  The “Setup” section of my Force.com application provides me access to a host of options to create new things, customize existing things and turn all sorts of knobs that enable rich functionality.  Here I browsed to the “Contact” object and chose “Fields”.

2009.10.07force01

Next I created a few custom fields to hold a global identifier (across all my CRM applications), a contact preference and a list of technology interests of the contact.

2009.10.07force02

I then navigate to my “Contacts” page and see my custom fields on the screen.  I can move then anywhere on the screen that I like using an easy-to-use drag-and-drop interface.

2009.10.07force03

Now that my data object is complete, I want to create a web service that lets my on-premises ESB retrieve customers based on their Global ID.  Back within the Force.com “Setup” screens I chose to Develop a new Apex class.  Note that Apex is the C#/Java-like language used to write code for Force.com.

2009.10.07force04

My class, named CRMCustomer has a web service operation identified where I lookup the contact with the ID matching the service’s input parameter, and then deliver a subset of the full Contact object back to the service caller.  If you look closely you can see that some fields have a “__c” after the field name to designate them as custom.

2009.10.07force05

If my class is written successfully, I’ll see an entry in my list of classes.  Note that my class now has a “WSDL” link next to it.

2009.10.07force06

Ok, now I have the object and service that I need for BizTalk to call this Force.com service.  But, I still need to retrieve my service definition.  First, I clicked this WSDL link next to my Apex class and saved the WSDL to my BizTalk machine.  Every time that I call the Force.com service I need to pass an access token in the header.  The header definition can be found in the Enterprise WSDL, which I also saved to my BizTalk machine.

2009.10.07force07

I made a choice to cache the temporary Force.com access token so that each call to my custom service wouldn’t have to do two invocations.  I accomplished this by building a singleton class which expires its token and reacquires a new one every hour.  That class library project has a reference to the Salesforce.com Enterprise WSDL.

[Serializable]
    public static class ForceToken
    {
        private static DateTime _sessionDate = DateTime.Now;
        private static string _sessionId = string.Empty;
        public static string SessionId
        {
            get { return GetSession(); }
        }
        private static string GetSession()
        {
            DateTime now = DateTime.Now;
            TimeSpan diff = now.Subtract(_sessionDate);
            if (_sessionId == string.Empty || (diff.TotalMinutes > 60))
            {
                //TODO lock object during update
                //refresh token
                System.Diagnostics.EventLog.WriteEntry("Utilities", "Salesforce.com Session Refresh");
                string uname = "<sf account>";
                string password = "<sf password>";
                string securityToken = "<sf token>";
                SFSvcRef.SforceService proxy = new SFSvcRef.SforceService();
                proxy.Url = "https://www.salesforce.com/services/Soap/c/16.0";
                SFSvcRef.LoginResult result = proxy.login(uname, password + securityToken);
                _sessionId = result.sessionId;
            }
            return _sessionId;
        }
    }

Within my actual BizTalk project, I added a service reference to the Force.com custom WSDL that was saved to my machine.  Lots of things come in, including the definition of the session header and my modified Contact object.

2009.10.07force08

Notice that the response object holds my custom fields such as “Contact Preference.”

2009.10.07force09

I’m using an orchestration to first get the access token from my singleton, and then put that token into the WCF header of the outbound message.

2009.10.07force10

Inside the Assignment shape is the simple statement that populates the SOAP header of my Force.com service call.

CRMCustomer_Request(WCF.Headers) = "<headers><SessionHeader><sessionId>"+ Seroter.SwedenUG.Utilities.ForceToken.SessionId +"</sessionId></SessionHeader></headers>";

My send port was created automatically from the binding file produced when importing the Force.com custom WSDL.  This WCF-Custom send port uses the basicHttp binding to call the endpoint.

2009.10.07force12

Once I send a message to my orchestration which contains the “global ID” of the record that I’m looking for, the Force.com service is called and my record is returned.

2009.10.07force11

Cool.  That’s a live record in my Force.com application (shown in a screenshot earlier) and can be pulled on-demand via my service.

So what we know now?

  • Easy to set up a Force.com account
  • There is a straightforward interface to customize objects and build web services
  • BizTalk needs to request a time-limited token for it service calls so a singleton can introduce some efficiency
  • You can add the session header to the outbound message via a WCF context property accessor in an orchestration

Next up, I’ll show how I tie all this together with an web application hosted in Amazon.com’s EC2 environment and leveraging the Azure .NET Service Bus to communicate between Amazon’s public cloud and my on-premise ESB.

Share

Author: Richard Seroter

Richard Seroter is currently the Chief Evangelist at Google Cloud and leads the Developer Relations program. He’s also an instructor at Pluralsight, a frequent public speaker, the author of multiple books on software design and development, and a former InfoQ.com editor plus former 12-time Microsoft MVP for cloud. As Chief Evangelist at Google Cloud, Richard leads the team of developer advocates, developer engineers, outbound product managers, and technical writers who ensure that people find, use, and enjoy Google Cloud. Richard maintains a regularly updated blog on topics of architecture and solution design and can be found on Twitter as @rseroter.

14 thoughts

  1. In this senario where did u called SectionID in orchestration. before how to validate the Usename and password. there is no port(sessionID) in orchestration right ? Plz briefly explain the process flow in orchestration….

    Advance thanks to u.

  2. Richard,
    Another excellent example, thank you for posting it.

    Were you able to get the correct XPath for locating the Fault Message in the Messages section (Inbound BizTalk message body) of the WCF-Custom Send Port Properties?

    I get the following error when a fault is thrown:
    Error details: System.InvalidOperationException: Unable to find match for inbound body path expression

    I’ve tried the following expressions without any luck:

    “/*[local-name()=’Fault’]/*[local-name()=’Detail’]/* | /*[local-name()=’InvalidSObjectFault’]”

    “/*[local-name()=’Fault’]/*[local-name()=’Detail’]/* | /*[local-name()=’InvalidSObjectFault’ and namespace-uri()=’urn:fault.enterprise.soap.sforce.com’]”

    “/*[local-name()=’InvalidSObjectFault’ and namespace-uri()=’urn:fault.enterprise.soap.sforce.com’]”

    Thanks.

  3. Hi Richard,
    I tried this same approach. I followed writing the Apex class. Except for downloading the wsdl for the class – i only copied the request and response schemas to the Biztalk project. I did not add a service reference. I created request/response messages and created a bidirectional port…etc..

    The binding in the port i used was the same wcf-custom with basic http.

    The one advantage is that all the unrequired types are not created and you can keep your local types small and more readable. You can also choose selectively keep certain complex types based on the objects getting returned.

    The entire wsdl otherwise is too huge…
    I am on Biztalk 2006 R2 now..

    Your article above was very very helpful …!!

  4. Hi Richard
    I am trying this to create an account in the Salesforce.com.I am getting the Session id generated from Soap UI and hard coding in the Assignment shape.Does this make any difference because at the end it was saying invalid session ID.but the session id is generated below 1 hr nd when i check back its still the same session ID.My expression in the Message Assignment is like this
    MsgCreate(WCF.Headers) = “”+”the session id i copied from SoapUI”+””;

    Any suggestions where i am going wrong.Advance Thanks

    Regards
    Narri

  5. Narri, not necessarily sure why you are getting the invalid session ID. Any chance you have an “invalid” ID vs. an “expired” ID? That is, could there be any encoding on the returned value that isn’t transferring correctly to your assignment shape?

    1. Hi Richard,
      Actually i got result here for your demonstration.. i had a custom wsdl which is developed in APEX ..It worked for me with that..The problem exists only when I am trying to integrate to Enterprise WSDL ..either i get INVALID SESSION ID for outbound WCF message body type is body or if i change the Outbound WCF message body type to template and give

      i will get No operation available for request {}create.I am trying to get with SF guys.Any suggestions from you

      Thanks
      Narri

      1. Hi there – I know this is an old article, but just as a quick question – any reason you didn’t just consume the standard Salesforce SOAP API and use a SELECT query with a LIMIT 1 to send your GlobalID and return the Contact? That way, no Apex would have been required at all and it would be more adaptable to future changes.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.