Integrating Salesforce Outbound Messages and C# in Visual Studio 2017

Rachel Soderberg - Feb 17 '19 - - Dev Community

Most Salesforce systems require some kind of integration between Salesforce and one or more backend systems, such as databases, other CRMs, or ERPs. There's a few different ways this integration can be done, but today I am focusing on integrating with Salesforce using Workflow Outbound Messages and C# .NET in Visual Studio 2017.

This integration method assumes that:

  • Salesforce is the creation point for accounts (not the ERP)
  • Any updates to accounts in Salesforce are reflected in the ERP when they exist

Salesforce Workflow Outbound Messages
The first major step is to create a Workflow Rule in Salesforce:

  1. Click Setup in the top right corner and type "Workflow Rules" in the search bar to the left. (Setup > Build > Create > Workflow & Approvals > Workflow Rules)
  2. Click New to create a new rule, selecting the Quote object from the dropdown. Give it a clear rule name such as "Quote Update On Create."
  3. Set the Evaluation Criteria to "created, and any time it's edited to subsequently meet criteria. This means the rule will be evaluated when a record is created and also when a record is edited from a state that doesn't meet the Rule Criteria into a state that does meet it.
  4. Set the Rule Criteria to run this rule if the "formula evaluates to true" and include the following function in the field:   

    NOT( ISBLANK( Order_XML__c ) )

    There are many other functions one could use in this field; some prefer to simply enter "True" as it provides a one-time update when the Quote is created. I chose the function where the Custom Order XML is not blank because this allows for easy updating if you delete this custom field from the Quote and click Save. This action causes the XML to regenerate, and as such, meet the rule criteria and run the rule.
  5. Click "Save & Next" to be redirected to the next steps.

Workflow Rules

The second major step requires you to create a Workflow Action:

  1. Click Add Workflow Action and select New Outbound Message from the dropdown.
  2. Once again, give your Outbound Message a clear name such as "Quote Create." This will automatically fill in the Unique Name.
  3. Provide a dummy Endpoint URL for now. www.google.com should be fine.
  4. Select your User to send as - this should be you.
  5. Add any Available Fields to the Selected Fields column using the Add arrow. I suggest sticking to only a couple for the sake of this tutorial - I chose AccountId and Id.
  6. Click Save to be redirected back to your finished Workflow Rule, where you will then click Done in the right hand corner of the view. Workflow Actions
  7. Now that you're back on the Workflow Rule page, be sure you click the Activate button to activate your workflow!
  8. Navigate to your finished Outbound Message by clicking the hyperlink included on the Workflow Rule under Immediate Workflow Actions and click the "Click for WSDL" hyperlink. Outbound Message
  9. Save this WSDL (File > Save Page As) and use a clear name. I called mine quoteCreateWorkflowOutboundMessage.wsdl.

I would like to mention that because you assigned a dummy URL to the Endpoint, your Outbound Message will be triggered and fail whenever a new Quote is created or the custom Order XML field is deleted and re-generated. This is expected, don't worry! Our next step is to build a .NET service to communicate with it.

WCF Web Service Application
From this point on, there may be differences depending on your version of Visual Studio. This blog post is written with Visual Studio 2017 Professional Edition; if you would like to use Visual Studio 2013 Community Edition, follow this link to an excellent blog post (and the inspiration to the one you're reading now) by Giovanni Modica: Salesforce Workflow Outbound Messages Handled in .Net with WCF(VS2013)

Our first set of steps on this side of our integration is creating our WCF application:

  1. Launch Visual Studio and create a new C# ASP.NET Web Application. I named my project QuoteNotificationService. New ASP.NET Web Application
  2. Choose an Empty project template and click OK. Empty Project Template
  3. Add a WCF service to the project by right clicking the project name in Solution Explorer. Add > New Item > WCF Service. I named mine QuoteService. Add WCF Service You should now see three new files in your solution similar to mine: IQuoteService.cs, QuoteService.svc, and QuoteService.svc.cs.

Now that we have our application ready to go, we need to add the WSDL we saved from Salesforce to our project. This can be a little tricky, don't worry if it takes you a couple of tries to get it right:
Open a command prompt window at the folderlocation of svcutil.exe - mine is located at C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin but yours may be different depending on where Visual Studio is located on your own environment. Run a file search if you can't find it. Open the command prompt by clicking within the address field and typing "cmd."

WCF svcutil is a .NET Core CLI tool that retrieves metadata from a WSDL file or web service on a network location and generates a WCF class containing client proxy methods that access the web service operations WCF dotnet-svcutil tool for .NET Core.

Enter the following into the command prompt:
svcutil /noconfig /out:C:\..\IQuoteNotificationService.cs C:\..\quoteCreateWorkflowOutboundMessage.wsdl
Note: You must include the full location path of the Interface class and the WSDL file.

On success, the command will have replaced the contents of your Interface class with the web service definition of your WSDL from Salesforce. It will print out which files have been generated:
svcutil File Generation
The command has successfully replaced the contents of your Interface class.

Click Yes to All if Visual Studio asks you to reload the editor.

Your Solution Explorer should look similar to this:
Solution Explorer

Your WCF application now requires a few finishing touches before it is ready to receive data from Salesforce. Any names I use from now on will reflect those in my Solution Explorer. If yours are named differently, be sure you change my names to those of your project. Open your Interface class and make the following changes:

  1. Put the whole class inside of the namespace of the project (QuoteNotificationService).
  2. Change the name of the interface from NotificationPort to IQuoteService.
  3. Change the ConfigurationName parameter of the ServiceContractAttribute from NotificationPort to QuoteService.
  4. Remove the parameter ReplyAction="*" from the OperationContractAttribute attribute.
  5. Remove the interface NotificationPortChannel and the class NotificationPortClient from the end of the file. These are unnecessary for our situation.

Now open QuoteService.svc.cs, remove the DoWork() method, and implement the IQuoteService interface by clicking in the IQuoteService inheritance and choosing the "Implement missing members" prompt when it pops up. This dialog may pop up in a lightbulb, or you may have to manually show it using Ctrl+).

Next open your web.config file and modify it to the following:
web.config
The most significant changes are the addition of the ERP to the connection string and the addition of the service name.

At this point, you should be able to build your project without errors!

Finally, our last step is to write the code that will update our ERP. This code will vary widely by how you update your ERP, so I will provide simply the boilerplate code. Write the following code in your QuoteService class:
QuoteService.cs

Be sure your Ack variable is set to a true response; Salesforce requires this acknowledgement in order to process the Outbound Message successfully.


Now that you have a functioning Outbound Message with Workflow Rules on Salesforce and a WCF Web Service ready to talk to it, the next step will be to test the connection and send some data back and forth!

Join me next week for Part 2 of this series if you're ready to learn about SOAP requests and testing a Web Service.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .