Simon Fell > Its just code > Outbound Messaging with .NET 1.1

Monday, February 12, 2007

As I mentioned way back in April 2003, wsdl.exe /server is basically useless. This is fixed in .NET 2.0, and wsdl.exe /serverInterface works pretty much as you'd expect (or at as I'd expect, which is good enough for me). If you're trying to use the new Outbound Messaging feature that was part of the recent Winter release, and you're still on .NET 1.1, then you'll run into this real fast. For those who haven't seen the feature, basically you specify some condition to send you a message, you define what fields you want in the message from the target object, and we generate a WSDL that represents the messages we'll send you. You feed this wsdl into your tool of choice to spit out your server skeleton, and off you go. Well, unless you're on .NET 1.1, where its not remotely obvious what to do. So, here's a quick guide to getting up and running with Outbound Messaging and .NET 1.1.

  • Stop, why are you still on .NET 1.1? are you sure you can't move up to 2.0, you should seriously investigate this first.
  • Ok, if you're still here, go into the Salesforce.com app, setup, workflow and setup your rule and outbound message, in the message pick the fields you want (I picked the Contact object and the firstName & lastName fields).
  • Right click on the "Click for WSDL" link, and save it somewhere.
  • From the command line, run wsdl.exe /server om.wsdl to generate the stub class and types file (it'll be called NotificationService.cs by default)
  • You'll notice that the generated class is abstract, but don't fall for the trick of creating a concrete subclass, its not going to work.
  • Horrible as it is, the easiest way forward is to now modify the generated code, remove the abstracts, and add an implementation to the notifications method, here i'll just copy the contact objects to a static list so i can have another page view the list of contacts i've received.
    [System.Web.Services.WebServiceBindingAttribute(Name="NotificationBinding", Namespace="http://soap.sforce.com/2005/09/outbound")]
    [System.Xml.Serialization.XmlIncludeAttribute(typeof(sObject))]
    public class NotificationService : 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 n) {
        	foreach(ContactNotification cn in n.Notification) {
        		lock(objects) {
        			objects.Add(cn.sObject);
        		} 
    	}
    	notificationsResponse r = new notificationsResponse();
    	r.Ack = true;
    	return r;
        }
    
        private static System.Collections.ArrayList objects = new System.Collections.ArrayList();
        
        public static System.Collections.ArrayList CurrentObjects() {
        	lock(objects) {
        		return (System.Collections.ArrayList)objects.Clone();
        	}
        }
    }
  • Next up you need to compile this into a dll, run csc /t:library /out:bin/om.dll NotificationService.cs (this assumes you've already created the bin directory that asp.net needs). Now you can wire it up as a webservice, you can do this by editing the web.config to map a URI to the class, or just use a dummy asmx page that points the class, that's what i did, here's om.asmx
    <%@ WebService class="NotificationService" %>
  • At this point you should be able hit hit the asmx page with a browser and get the regular .NET asmx service page.
  • Next, we'll add a simple aspx page that can access the static objects collection and print out the details from the messages it got. (obviously a real implementation should do some real work in the notifications method, but this is a handy test)
    <%@ Page language="C#" %>
    <html><head>
    </head><body>
    <h1>Recieved Contact ids</h1>
    <%
    foreach(Contact c in NotificationService.CurrentObjects()) {
    	Response.Write(string.Format("{0} {1} {2}<br>", c.Id, Server.HtmlEncode(c.FirstName), Server.HtmlEncode(c.LastName)));
    }
    %>
    </body></html>
  • That's it, go into the app, trigger your message, and refresh the aspx page to see the data from the message we sent you.

A slightly cleaner approach is to actually do the subclass, and to copy over all the class and method attributes to the subclass as well, at least then you can easily re-run wsdl.exe if you need to (say if you changed the set of selected fields).