[Looking for Charlie's main web site?]

CF8 Hidden Gem: Refreshing Web Service WSDL and CF proxy/stub with new RefreshWSDL option

One of the many hidden gems in CF8 (and I've found dozens of them) is a new attribute on CFINVOKE or CFOBJECT (and argument for createObject) called RefreshWSDL. It's a another solution to the long-standing problem of invoking web services whose metadata may have changed since previous executions. I'll explain the older approaches, some new in CF 6 and 7, later here for those who missed them.

So what's the problem it solves? If you have CFML code that calls a web service, and one day it just stops working, the problem may be that the web service itself has changed. Perhaps the owner changed the return type or some other metadata.

The new solution allows you to refresh that WSDL on the CFINVOKE or CFOBJECT tags, or the createObject method.

Doing it in CFINVOKE/CFOBJECT

Here's how to do it in CFINVOKE.

<cfinvoke webservice="http://[server]/[webserviceurl]" method="[methodname]" refreshWSDL="yes" ...

Adding it as an attribute for CFOBJECT would work essentially the same way, for those familiar with that tag.

Doing it in createobject()

Doing it in the createObject() function, however, is quite a bit different and leverages some new syntax for that function. I'll show that in another blog entry and will point out another new feature for that function.

There are a couple more points to consider about this, but first I just want to explain why it's needed, for those who haven't heard of such options.

Why should you have to refresh the web service metadata?

Just to back up for a moment, the problem stems from CF's attempt to help. On the first request for a given web service, CF does some caching to make future requests go faster, not caching the results of the web service method but rather the artifacts used by CF based on the description of the web service itself.

CF uses the web service description (WSDL) reported at the time of that first call to create a java proxy/stub based on that, which it then reuses on future calls from CF to that web service.

The issue arises if/when the web service metadata changes. CF won't know, and will continue to use the older cached proxy/stub, and your long-running code may fail if it doesn't match the new WSDL returned by the web service.

So we need a way to tell CF to refresh its cache of that proxy stub.

This new feature is certainly the easiest way to make that happen, but it's not the only way.

Not the only way to refresh the cache, but the easiest

Some may know (and I've written previously) about two programmatic ways to refresh the proxy/stub, whether you're using CF7 (which added a new method in the Admin API) or using CF 6 or above (using an undocumented/unsupported service factory method), as well as an available button in the CF Admin console that could do it (since CF6).

A benefit of this new approach is that it doesn't require you to know the CF Admin password.

Easier, yes, but could be used inappropriately

Of course, with power comes responsibility. You don't want to leave this indicator in your code for all requests, such as in production. That would force CF to do extra work on each web service invocation, defeating the whole purpose of the caching. It's like the tools CFLOG or CFTRACE. Well, more like the former. At least the latter has an Admin console option to disable it even if left in production code.

It's one of those things where opinions will differ. On the one hand, the ease of mistakenly leaving this in to get into into production could make one argue that it ought not be in code, or at least should not be in code calling the web service but rather code to manage the cached stub itself, which is what the previous features did.

On the other hand, those required admin access to perform (except for the unsupported servicefactory approach). Similarly, even if there WAS an option to disable refreshwsdl in production, you'd be stuck if you needed to refresh the cache in production and had no admin access.

At least we have the choices now, and forewarned is forearmed.

Finally, as for more CF 8 hidden gems, I'll note that I've got a user group presentation on the topic, and I have a few dozen more I share. I'll start sharing more of those in blog entries.

Comments
Of course you may prefer to completely bypass ColdFusion's rather unreliable method of dealing with web services by generating stub files, which can simply not work sometimes when your consuming JAVA, .NET or other web services not written in ColdFusion.
The generation of the stub files can be a very time consuming process, especially for a complex WSDL, so presuming there are no errors that cause the stub generation to fail, you could be waiting several minutes for this to happen every time you refresh the web service.
A quick and easy way around this is to generate your own SOAP requests and use CFHTTP to post it. This is in fact quicker and easier than figuring out how to create a complex ColdFusion structures of arrays that matches what is defined in the WSDL.
Just download a neat little tool called SOAPUI, and use this to interrogate your WDSL and it will create a default request. Copy that request over to your CFML template and fill in the variables, and voila.
More details on my blog here: http://russ.michaels...
# Posted By Russ Michaels | 9/3/07 7:23 PM
Wow. Well, sure, if one wants to jettison calling web services from within CFML using CFINVOKE/CFObject/createObject, there are indeed options, so thanks for sharing that for those who hadn't considered it.

I should say that just as in most aspects of CFML, while there are aspects where a feature may not suit everyone, it likely still suits most, so let's not give folks the impression that they ought to skip the more traditional ways to call them. :-)

Also, you say, "you could be waiting several minutes for this to happen every time you refresh the web service", but really the thinking here is that one would do this rather infrequently (like once after a period of months).

More important, web service providers should be careful about altering their public interfaces, making this need even less likely. I should have made that point in the entry.
# Posted By Charlie Arehart | 9/4/07 1:04 AM
Please note that I have not suggested that anyone should NEVER use CFINVOKE or should abandon CF's native invocation methods altogether, I have simply given a scenario and an alternative. Whyile I of course love CFML as much as the next person, I accept the fact that sometimes it can be akin to using a crowbar to open a tub of margerine, which is not always the best solution.
# Posted By Russ Michaels | 9/4/07 3:58 AM
Yep, I realized that's what you were writing. You said it was for when it would "not work sometimes", so that's why I thanked you. I also recognized your suggestion as addressing "aspects where a feature may not suit everyone". I only reply with clarification if I think some readers may benefit.
# Posted By Charlie Arehart | 9/4/07 4:14 AM
This is an awesome feature, Charile. Thanks for pointing it out; I totally missed it.

As for production versus development, currently I wrap webservice calls in a try catch block that refreshes them using the old method, retries the call, and rethrows if there is still a problem.

My guess is that you may still want to do something similar to that.
# Posted By Terrence Ryan | 9/4/07 9:41 AM
Thanks, Terrence.
# Posted By Charlie Arehart | 9/4/07 10:34 AM
Apologies for commenting 7 months later, but from a security angle is it possible to stop the ?wsdl bit of a url from exposing the parameters of the web service?

I read a security article ( http://www.regdevelo... ) and the hackers found adding ?wsdl very helpful when trying to exploit web services.
# Posted By Gary F | 4/14/08 8:40 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.005.

Managed Hosting Services provided by
Managed Dedicated Hosting