Simon Fell > Its just code > Web Services
Monday, November 12, 2007
Don Box on AuthI found it hilarious that Don moans about HTTP auth and then points to WS-Security as the way forward, I just can't decide if Don was trying to be funny, or is actually serious. (in which case he's been in Redmond too long), looks like I'm not the only one.
Friday, May 04, 2007
Salesforce Developers ConferenceIs coming up fast, May 21st in Santa Clara, CA. This is a great chance to get up to speed with Apex Code, and other parts of the Salesforce.com platform, As well as the regular ADN crew, I'll be there along with some other folks from the API team, so bring your Apex Code, API and Web Services questions, best chance to get answers straight from the horse's mouth before Dreamforce. Best of all, its Free, sign up now.
Saturday, April 28, 2007
Team Hanselman and Diabetes Walk 2007
| Scott Hanselman is again doing the Diabetes Walk, and this year is stepping up his goal to $50,000, go ahead and help him meet the goal. To the Salesforce.com folks out there, remember that they'll match your contribution, and I'm sure many other employers do as well, an easy way to make your money go twice as far. |
Thursday, April 05, 2007
The devil is in the wrong details.Paul Fremantle has a post titled the devil is in the details, where he discussed interop issues around wrapped vs unwrapped WSDLs. Unfortunately that's totally missing the point, Why on earth should the service provider get to dictate to me what programming model i want to use? why do the tools insist on trying to divine a programming model from the WSDL, when it should be the programmers choice!, give me a switch in WSDL2Java or wsdl.exe that says generate me a wrapper or unwrapped stub.
Monday, February 12, 2007
Outbound Messaging with .NET 1.1As 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).
Saturday, January 27, 2007
PocketHTTP updatedThe release train rolls on, I just posted an updated version of PocketHTTP to address a couple of issues, (i) you could still get bogus gzip errors because under certain conditions it would apply the crc calc out of order and (ii) there was an issue with how the connection pool managed proxied SSL connections, that would result in it giving you the wrong connection if you trying to do proxied ssl to multiple different target hosts.
Wednesday, January 17, 2007
Apex Web ServicesI was at Apex day in San Francisco yesterday, there was an impressive turn-out, I saw lots of new faces, along with a few familiar faces from Dreamforce. Developer's at the event were lucky enough to be able to signup for the developer prerelease of Apex Code. In addition to the support for triggers that Apex Code brings, Apex Code also supports exposing your code as a fully fledged web service, complete with WSDL, and powered by the same high performance, highly interoperable web services implementation that drives the primary salesforce.com API. In Apex code the private/public specifier has an additional option, its actually private/public/webService. Simply create your code in a package, and mark the method as webService, e.g.
package wsDemo {
webService String sayHello(String name) {
return 'Hello ' + name;
}
}
and you'll have a complete WSDL for calling this code. Of course, no one needs a web service to do string concatenation, where this really comes into its own is build your own transactional units for doing integrations. Anyone who's built a complex data integration with salesforce (or any other distributed system) knows the pain of trying to manage transactional units that are different at the both ends, and having to build compensating transactions etc. Simple examples like creating an opportunity and all its line items in a single transactional unit could of been achieved by evolving the existing API, however more complex uses cases, where the developer needs to update 5 objects, delete 3 and create 1 new object all in a single transaction, just can't be handled by evolving the existing API. But, now you can build your own API's that have exactly the transactional boundaries you want. In Apex Code, you the developer control the transactions, so you can write a method that receives all the data needed as inputs, it can do a number of data operations, including create, update, delete, using data from both the request, and existing data in the system, then at the end only commit if everything went ok. Using Apex Code with its Web Services support I think will be a really powerful and easy way to do complex data integrations. Here's an Opportunity / LineItem sample, as the calls to insert will throw an exception if there's an error, and if the exception leaves your code, your transaction is rolled back, the entire call will either fully succeed or fail.
webService ID createOrder(Opportunity o, OpportunityLineItem [] items) {
insert(o);
for (OpportunityLineItem i : items) {
i.opportunityId = o.Id;
}
insert(items);
return o.Id;
}
Sunday, December 24, 2006
new buildsCouple of new builds out with some minor bugs fixes, first up, a new build of PocketHTTP that fixes an intermittent problem some people had seen when its reading gzip compressed responses. Second up, an update to SF3, this fixes a problem caused by a particular combination of contact details in address book on initial sync, it also addresses a problem with reading all day events from salesforce and them ending up with the wrong date in iCal. Next time you start SF3 it'll tell you about (and offer to install) the updated version, assuming you left the check for updates preference on. Right now I'm suffering from having way more idea's than time to work on them. Happy Holidays!
Thursday, December 07, 2006
Compression in .NET 2.0 Web Services ClientsOver on ADN there's a tech note that explains how to add request & response compression support to .NET generated web services clients. As .NET 2.0 provides support for response compression out the box now (once you've turned it on), you'll find this code fails on .NET 2.0 because it ends up trying to decompress the response twice. So I updated the code for .NET 2.0, it now only has to handle compressing the request. The nice thing about the approach it takes (subclassing the generated proxy class), is that you don't have to change the generated code at all, so it doesn't matter how many times you do update web reference, you'll still be in compressed goodness. So, all you need is this one subclass wrapper around your generated proxy class and you're good to go.
class SforceGzip : sforce.SforceService
{
public SforceGzip()
{
this.EnableDecompression = true;
}
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
return new GzipWebRequest(base.GetWebRequest(uri));
}
}
Then in your code that uses the proxy, just create an instance of this puppy instead of the regular proxy, e.g.
sforce.SforceService svc = new SforceGzip();
sforce.LoginResult lr = svc.login(args[0], args[1]);
All this is included in the sample project in the download, share and enjoy, share and enjoy
Tuesday, November 28, 2006
API Authentication ListScott over at Perspectives on Salesforce has a post about an API Authentication List feature, a way to restrict what API based applications can do. This is something I've been thinking about a lot, allowing application white listing (i.e. you can use Outlook Edition and Offline, but not the data loader or sf3), or Application X only requires access to accounts, make sure that's all it can access. All great ideas and features, but wait, how can the API server tell that the application making the request is in fact Outlook Edition and not SoqlXplorer ? The problem is that while you can authenticate a person, authenticating an application it impossible to do 100% securely (unless the client OS has TPM, and it can authenticate the application for you).
In his idea's exchange entry, Scott has a screen shot from Flickr which provides some similar features. If you go look at the Flickr authentication spec you'll see that it identifies applications using a shared secret, this secret never goes over the wire, so that's good, and if the application is another web based application, then its reasonable to assume that the secret is reasonably secret, you've got to hack the web app server to try and find the secret. However for desktop client applications, that shared secret has to be on the client machine somewhere, and in that case, its not reasonable to assume its safe, any determined person will be able to dig the secret out of where ever you've stashed it away. (and today's threat model is that it only take one determined person to work it out and post it for all to find, not that everyone has to work it out themselves)
Is that secure enough? I don't know, it largely depends on what you're trying to prevent. To stop people trying out random applications on their production data, yeah, I'd think so. To stop a 3rd party application stealing all your data? not if they were determined enough, to stop a disgruntled employee who's about to quit and want to take a copy of all the sales data with them? would likely depend on how well they can drive google. What other options are there? well a blanket profile level API access enabled yay / nay would work, although I'd suspect this is only useful in a fairly small subset of cases.
Tuesday, November 21, 2006
zkSforceI ended up building my own Cocoa client library for accessing the Salesforce.com API, I decided a while back I'd open source this, I just posted the first version. This is the library that powers both SoqlXplorer and SF3. Its released under the uber liberal MIT license, so have at it. Feedback welcome.
Thursday, November 16, 2006
SoqlXplorerSoqlXplorer 0.7 is out, it include the fruits of the UI rework labor, and of course the new schema explorer. If you have an older build installed, you fire it up and it'll prompt you to upgrade and do all the work for you.
Wednesday, November 08, 2006
.NET headers remix editionIn his post Trade-Offs, Sam points to my post last year on trying to have SOAP headers with simple types in .NET. In the comments Asbjørn Ulsberg claims that the behavior is related to handling nulls, and that its fixed in .NET 2.0. Well, lets see shall we.
To start with, the header defined is not nillable, therefore that's a complete read herring. as a reminder, here's the element definition that's detailed in the post and in the WSDL.
<s:element name="ValidFrom" type="s:dateTime"/>
I fired up .NET 2.0's WSDL.exe tool and pointed it at the first wsdl (you can play along at home if you want to)
C:\sampleCode\dotnet20_headers>wsdl http://www.pocketsoap.com/weblog/2005/08/test_1header.wsdl
Microsoft (R) Web Services Description Language Utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'C:\sampleCode\dotnet20_headers\TestService.cs'.
And lets take a look at the generated code
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2001/XMLSchema")]
[System.Xml.Serialization.XmlRootAttribute("ValidFrom", Namespace="http://test.sforce.com/", IsNullable=false)]
public partial class dateTime : System.Web.Services.Protocols.SoapHeader {
private string[] textField;
///
[System.Xml.Serialization.XmlTextAttribute()]
public string[] Text {
get {
return this.textField;
}
set {
this.textField = value;
}
}
}
Looks remarkably like the .NET 1.1 version (except for the fields vs properties thing), so, no, not fixed, not any better.
Thursday, October 26, 2006
SOAP Interop - the devil's still in the detailsApparently the problem with .NET remoting putting char 0 in a fault message from 4.5 years ago is still an issue. (and no, there's still no magic switch to allow PocketSOAP to parse stuff that looks like it might be XML, but isn't XML).
Thursday, October 12, 2006
Dreamforce wrap upDreamforce is over for another year, a hectic, fun packed few days, the highlights for me were
- Finally announcing the API 8.0 features, this is probably the most significant API version with the possible exception of the original release of the doc/literal SOAP API (back at API v2.5). There's a ton of good stuff in there including being able to query over relationships between objects, being able to resolve foreign keys using externalIds during upsert, having workflow trigger soap notifications, merge, undelete, and numerious additional improvements to SOQL, SOSL and metedata describes.
- Getting my hands on a copy of the new building applications book, it looks really good, and includes a sneak peak of Apex, congrat to all involved in putting it together.
- The Apex announcement, which seemed to go down really well, everyone I talked to at the conference was really excited about it. I'm looking forward to getting this into developers hands.
- Putting faces to the blogs, I got the chance to hang out and drink beer (and fail misserably at the trivia quiz!) with a bunch of the Salesforce bloggers, including Mark from Salesforcewatch, Scott from perspectives on Salesforce, fellow brit Gareth Davies from where's the upside amongst others.
- Getting asked coffee questions by multiple folks!
- Getting to be part of the dive into Apex session which was standing room only.
- My 3rd year at the Meet the developers session, a dreamforce tradition.
- The ADN@DNA party was a blast, arrgg pirate booty
See you next year!
