[Looking for Charlie's main web site?]

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

Note: This blog post is from 2007. Some content may be outdated--though not necessarily. Same with links and subsequent comments from myself or others. Corrections are welcome, in the comments. And I may revise the content as necessary.
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.

For more content like this from Charlie Arehart: Need more help with problems?
  • If you may prefer direct help, rather than digging around here/elsewhere or via comments, he can help via his online consulting services
  • See that page for more on how he can help a) over the web, safely and securely, b) usually very quickly, c) teaching you along the way, and d) with satisfaction guaranteed
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...
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.
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.
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.
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.
Thanks, Terrence.
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
With CF 11 you no longer get a listing of wsdl's in the admin. In Cf9 we had code that we could run to clear the cached wsdl's. Apart from just restarting the CF11 instance is there any programmatic way to do this in CF11?
# Posted By Alex | 6/3/15 12:47 PM
Alex, yes. Nothing new for 11, but you can use the same things introduced in 6 and improved in 7 and 8. See my past blog entries from that timeframe:

Reloading CF web services programmatically, using the CF7 Admin API
http://carehart.org/...

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

and

CF8 Hidden Gem: New ArgStruct argument for createObject with web services
http://carehart.org/...

Let me know if that helps.
Doh, I just noticed that Alex's question was with regard to the very blog post I was pointing to. Sorry. Getting old (53 tomorrow).

And I see you saying now, you had "code that we could run to clear the cached wsdl's". So I guess you're saying that somehow that code worked in 9 and does not in 11.

I don't know anything in 11 (or 10) that should have changed how these various features (the attribute, the Admin API, or the old undocumented objects) should have worked.

That said, it's worth nothing if your "old code" was indeed relying on those undocumented objects in CF (mentioned in my oldest post listed above), then you may find that it "doesn't work" in 10 or 11 simply because someone installed CF with the "secure profile" enabled. One of the things that does is disable those undocumented "internal java objects" within CF. That's good for security. Not so good if you had tools relying on them.

BTW, this ability to enable/disable them is in fact a long-existing option on the CF Admin "Settings" page, so it's not new in 10/11 that they can be disabled. Just new that they are off by default, if you turn on "secure profile".

Anyway, I did have some more thoughts all this, about clearing the caches.

First, FWIW, the fact that web services no longer appear in the Admin, by default just when you execute them, is not new to 11. I think it started in 10. One certainly CAN still define them there, for the purpose of then using a simple name to refer to the web service (just like datasource names allow simple reference to database definitions), though it's a rarely used feature I think.

But the bottom line is that web services are no longer there automatically just because one calls a given web service. And I see how you may have relied on that interface to refresh the stubs.

Even if somehow the refreshwsdl attribute doesn't work for you (and it has its warts, as I discuss in the blog post), or the internal java objects are disabled, you should certainly be able to use the Admin API to refresh them. Again the oldest post I point to above does show how to use the Admin API to refresh the stubs for a specific WSDL URL (which too has some challenges I discuss there).

Now that I think of it, you may want to create a feature request for Adobe (bugbase.adobe.com) asking them to add an interface to the Admin to let you a) name a web service to clear (like the template cache feature lets you point to a folder whose templates are to be refreshed). You shouldn't have to define the web service just to be able to refresh its stubs.

Indeed, you could go further and ask them to b) provide a UI to list all cached stubs (whether "defined" on that page or now) along with a corresponding Admin API call, to let you c) see them and or d) just clear all the cached stubs. I'm sure sometimes people will want to do that. (But clearing them one by one would generally be better, if only you could do it easily there and see a list of all of them.)

Hope that's helpful.
Copyright ©2024 Charlie Arehart
Carehart Logo
BlogCFC was created by Raymond Camden. This blog is running version 5.005.
(Want to validate the html in this page?)

Managed Hosting Services provided by
Managed Dedicated Hosting