Sunday 13 May 2007

SMS Alerts from Salesforce [2] - Creating the Web Service

Once you've defined the outbound message and specified and Endpoint URL, when you view the definition you'll see a link to the WSDL. This is the interface definition for the web service that the service generation tool will require to create the web service code.

The .net framework SDK ships with a file called wsdl.exe. This is most often used for generating web service client proxies but used with the /server switch, it generates an abstract server class that forms the basis of our web service. In the default installation of Visual Studio 2005, it can be found in C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin.

So I downloaded the WSDL to a file call CaseAlert.wsdl and ran the following command line

wsdl.exe /server CaseAlert.wsdl

This created a file called NotificationService.cs containing the abstract service class and supporting data types to enable the service to receive calls from the Salesforce systems.

I then created a web project called salesforcelistener and dragged the NotificationService.cs file into the App_Code folder. My initial thought was to create a new WebService called CaseAlert in this project and inherit from the abstract NotificationService class.

Unfortunately this didn't work, the methods of the base class were not exposed as a web service methods. I'm guessing this is because of the reflection algorithms that are used to generate the WSDL. So I deleted the CaseAlert code behind page and turned the NotificationService into a concrete class for the CaseAlert web service.

[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")]
[System.Web.Services.WebServiceAttribute(Namespace = "http://soap.sforce.com/2005/09/outbound")]
[System.Web.Services.WebServiceBindingAttribute(Name = "NotificationBinding", Namespace = "http://soap.sforce.com/2005/09/outbound")]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(sObject))]
public class CaseAlert : System.Web.Services.WebService
{
[System.Web.Services.WebMethodAttribute()]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute("notificationsResponse", Namespace = "http://soap.sforce.com/2005/09/outbound")]
public notificationsResponse notifications([System.Xml.Serialization.XmlElementAttribute("notifications", Namespace = "http://soap.sforce.com/2005/09/outbound")] notifications notifications1)
{
return new notificationsResponse();
}
}

Fired up the project and success:

Test Harness

Rather than use Salesforce workflows to generate test messages, and potentially annoy the live users of the system, I generated a harness so test messages could be fired at will. As this is essentially a web service this is incredibly simple.

While the web service project was running, I created a new console application project. Created a web reference from this to my web service (called salesforceoutbind) so I can make calls as required.

Remember the Session ID, this is value returned in response to a successful login request to the Salesforce API and can then be used for all subsequent calls to the API. So I added in the proxy cs file supplied with in the Salesforce sample C#.net application which includes all the code required to set this up.

The code for my console app is below. Logging and error handling excluded for brevity.

static void Main(string[] args)
{
SforceService salesforceBinding = new SforceService();
// amend these with your details
LoginResult loginResult = salesforceBinding.login("user.name@company.com", "password");

salesforceoutbind.notifications n = new salesforceoutbind.notifications();
salesforceoutbind.CaseNotification cn = new salesforceoutbind.CaseNotification();
salesforceoutbind.Case c = new salesforceoutbind.Case();
cn.sObject = c;
c.AccountId = "00120000004SPkT";
c.CaseNumber = "001000";
c.Subject = "My New Case";

n.Notification = new salesforcelistenerclient.salesforceoutbind.CaseNotification[] { cn };

n.SessionId = loginResult.sessionId;

salesforceoutbind.CaseAlert alert = new salesforcelistenerclient.salesforceoutbind.CaseAlert();
alert.notifications(n);
}

I can now push messages to the listener with complete control over the data that is passed in. Next time I'll call back into the Salesforce API to get the contact details for the Account Manager and send them a message using the Esendex SMS XML Web Service API

No comments: