Sending Messages from BizTalk to Salesforce.com Chatter Service

The US football Super Bowl was a bit of a coming-out party for the cool Chatter service offered by Salesforce.com. Salesforce.com aired a few commercials about the service and reached an enormous audience.  Chatter is a Facebook-like capability in Salesforce.com (or as a limited, standalone version at Chatter.com) that lets you follow and comment on various objects (e.g. users, customers, opportunities).  It’s an interesting way to opt-in to information within an enterprise and one of the few social tools that may actually get embraced within an organization.

While users of a Salesforce.com application may be frequent publishers to Chatter, one could also foresee significant value in having enterprise systems also updating objects in Chatter. What if Salesforce.com is a company’s primary tool for managing a sales team? Within Salesforce.com they maintain details about territories, accounts, customers and other items relevant to the sales cycle. However, what if we want to communicate events that have occurred in other systems (e.g. customer inquiries, product returns) and are relevant to the sales team? We could blast out emails, create reports or try and stash these data points on the Salesforce.com records themselves. Or, we could publish messages to Chatter and let subscribers use (or ignore) the information as they see fit. What if a company uses an enterprise service bus such as BizTalk Server to act as a central, on-premises message broker? In this post, we’ll see how BizTalk can send relevant events to Chatter as part of its standard message distribution within an organization.

If you have Chatter turned on within Salesforce.com, you’ll see the Chatter block above entities such as Accounts. Below, see that I have one message automatically added upon account creation and I added another indicating that I am going to visit the customer.

2011.2.6chatter01

The Chatter API (see example Chatter Cookbook here) is not apparently part of the default SOAP WSDL (“enterprise WSDL”) but does seem to be available in their new REST API. Since BizTalk Server doesn’t talk REST, I needed to create a simple service that adds a Chatter feed post when invoked. Luckily, this is really easy to do.

First, I went to the Setup screens within my Salesforce.com account. From there I chose to Develop a new Apex Class where I could define a web service.

2011.2.6chatter02

I then created a very simple bit of code which defines a web service along with a single operation. This operation takes in any object ID (so that I can use this for any Salesforce.com object) and a string variable holding the message to add to the Chatter feed. Within the operation I created a FeedPost object, set the object ID and defined the content of the post. Finally, I inserted the post.

2011.2.6chatter03

Once I saved the class, I have the option of viewing the WSDL associated with the class.

2011.2.6chatter04

As a side note, I’m going to take a shortcut here for the sake of brevity. API calls to Salesforce.com require a SessionHeader that includes a generated token. You acquire this time-sensitive token by referencing the Salesforce.com Enterprise WSDL and passing in your SalesForce.com credentials to the Login operation. For this demo, I’m going to acquire this token out-of-band and manually inject it into my messages.

At this point, I have all I need to call my Chatter service. I created a BizTalk project with a single schema that will hold an Account ID and a message we want to send to Chatter.

2011.2.6chatter05

Next, I walked through the Add Generated Items wizard to consume a WCF service and point to my ObjectChatter WSDL file.

2011.2.6chatter06

The result of this wizard is some binding files, a schema defining the messages, and an orchestration that has the port and message type definitions. Because I have to pass a session token in the HTTP header, I’m going to use an orchestration to do so. For simplicity sake, I’m going to reuse the orchestration that was generated by the wizard. This orchestration takes in my AccountEvent message, creates a Chatter-ready message, adds a token to the header, and sends the message out.

The map looks liked this:

2011.2.6chatter07

The orchestration looks like this:

2011.2.6chatter08

FYI, the header addition was coded as such:

ChatterRequest(WCF.Headers) = "<headers><SessionHeader xmlns='urn:enterprise.soap.sforce.com'><sessionId>" 
+ AccountEventInput.Header.TokenID + 
"</sessionId></SessionHeader></headers>";

After deploying the application, I created a BizTalk receive location to pick up the event notification message. Next, I chose to import the send port configuration from the wizard-generated binding file. The send port uses a basic HTTP binding and points to the endpoint address of my custom web service.

2011.2.6chatter09

After starting all the ports, and binding my orchestration to them, I sent a sample message into BizTalk Server.

2011.2.6chatter10

As I hoped, the message went straight to Salesforce.com and instantly updated my Chatter feed.

2011.2.6chatter11

What we saw here was a very easy way to send data from my enterprise messaging solution to the very innovative information dissemination engine provided by Salesforce.com. I’m personally very interested in “cloud integration” solutions because if we aren’t careful, our shiny new cloud applications will become yet another data silo in our overall enterprise architecture.  The ability to share data, in real-time, between (on or off premise) platforms is a killer scenario for me.



Categories: BizTalk, Cloud, Salesforce.com, SOA

14 replies

  1. Chatter should be interesting as users begin to adopt it more and more. I am honestly still sceptical as to whether it will be adopted or not. I predict it might go the way of Google Wave – a fantastic idea with little real life application. Nice superbowl ads, but I noticed others in the audience with me were totally confused by the commercials – they had no idea what chatter is all about.

  2. Now that Chatter can be used without having to purchase SalesForce, I think we’ll see a lot more adopters, at least in the short-term. It’s a very intuitive, simplified interface–like facebook–and having an internal dynamic news feed is really nice. I like the idea of being able to send external messages to Chatter too–definitely a missing piece of functionality that people would actually use.

  3. Richard – your comment “shiny new cloud applications will become yet another data silo in our overall enterprise architecture.” is spot on in my view – one of the key drives for clients and consultants selling cloud solutions is obviously the cost savings to be made in the cloud, but not so much round opening up your architecture and data.

    I wonder if in 5 years time we will have a lot of applications “stranded” up in the cloud…

    • Thanks for the note Dom. Yes, I would suspect that it’s in any packaged app’s (SaaS or on-premises) best interest to put a significant amount of data/process into their platform, so it takes independent analysis to think about how to build an architecture that doesn’t creates isolated, stranded apps!

  4. Hi All,

    I am currently working on an integration solution integrating BizTalk with Salesforce standard enterprise wsdl service (I cannot use apex classes due to limitation from the client).
    Here are the implementation steps that I have followed:
    I have consumed standard enterprise wsdl fetched from Salesforce API
    Used the Static Solicit-Response soap port already created in orchestration from step1 to get the loginResponse from SFDC.
    Once the login was successful I have used construct and expression shape for dynamic port with below setting to get the query result from Salesforce for Account table

    construct shape:

    queryAccount=System.Configuration.ConfigurationManager.AppSettings[“querySelect_Account”];
    xmlDoc.LoadXml(@”+queryAccount+”);
    msgQueryRequest.parameters=xmlDoc;
    msgQueryRequest(WCF.BindingType) = “basicHttpBinding”;
    msgQueryRequest(WCF.SecurityMode)=”Transport”;
    msgQueryRequest(WCF.BindingConfiguration) = “”;
    msgQueryRequest(WCF.Action)=””;
    msgQueryRequest(WCF.Headers) = “” + msgLogResponse.parameters.result.sessionId + “”;

    Expression shape code is same as ealier:
    Port_EgmontDynamicPort_SfdcService_GetQueryResult(Microsoft.XLANGs.BaseTypes.Address)=msgLogResponse.parameters.result.serverUrl;
    Port_EgmontDynamicPort_SfdcService_GetQueryResult(Microsoft.XLANGs.BaseTypes.TransportType)=”WCF-BasicHttp”;

    I receive below Error in the BT Admin Console from orchestration (below). I am passing latest sessionid from loginResponse.
    Exception thrown from: segment -1, progress -1
    Inner exception: Received unexpected message type ‘http://schemas.xmlsoap.org/soap/envelope/#Fault’ does not match expected type ‘urn:enterprise.soap.sforce.com#queryResponse’.

    Sfdc Fault message:
    sf:INVALID_SESSION_IDINVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal SessionINVALID_SESSION_IDInvalid Session ID found in SessionHeader: Illegal Session

    Previously when i was not setting Action in the construct shape I got below error
    soapenv:ClientSOAPAction HTTP header missing

    Please let me know where I am going wrong in the above implementation and provide me your solution and suggestion ASAP.

    Thanking you in advance.

    Thanks & Regards,
    Nilesh Sawant

    • Have you traced the message that you are sending to SFDC? Can you see the token that you’ve added to the header?

      • Hi Richard,
        Thanks for reply. Yes Richard I have traced the message that I am sending to the SFDC. I can see sessionId populated with value and msgQueryRequest also populated with select query from bts config file but still getting the same error.

        Construct Shape
        selectAccount=System.Configuration.ConfigurationManager.AppSettings[“querySelect_Account];xmlDoc.LoadXml(@””+selectAccount+””);
        msgQueryRequest.parameters=xmlDoc;
        msgQueryRequest(WCF.Headers) = “” + msgLoginResponse.parameters.result.sessionId +””;
        msgQueryRequest(WCF.BindingType) = “basicHttpBinding”;
        msgQueryRequest(WCF.SecurityMode)=”Transport”;
        msgQueryRequest(WCF.BindingConfiguration) = “”;

        Expression Shape:
        Port_dynamicSFDC(Microsoft.XLANGs.BaseTypes.Address)=msgLoginResponse.parameters.result.serverUrl;
        Port_dynamicSFDC(Microsoft.XLANGs.BaseTypes.TransportType)=”WCF-BasicHttp”;

        Sfdc Fault message:
        sf:INVALID_SESSION_IDINVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal SessionINVALID_SESSION_IDInvalid Session ID found in SessionHeader: Illegal Session

        Regards,
        Nilesh Sawant

    • The header must be set as shown below and not with sessionId alone.

      msgQueryRequest(WCF.Headers) =”” + sessionId +””;

  5. Did u got any solution for this invalid session ID error?? currently im facing the same error.. help out pls

Trackbacks

  1. Distributed Weekly 89 — Scott Banwart's Blog
  2. Integrate with SalesForce « Think Integration

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: