Warning: I'm about to rant. If you prefer to skip the emotion, feel free.
As much as possible, I prefer not to criticize others, especially not in areas in which I myself am not expert, but I am thoroughly disappointed in Flex, at least in its ability to integrate with Coldfusion. RIAs have been coming into their own for quite some time now, and when I first heard about Flex (2), Adobe was fairly screaming about how easy Flex and Coldfusion worked together. I was very excited about the possibilities, and began preaching about revolutionary change in the web, the death of AJAX and possibly even of Desktop applications, especially with the ability to push data with Flex (or Live Cycle as it's now called) Data Services.
"Woo-hoo!" I thought, and imediately dove in. That was a month ago, and I've just today gotten a hello world app to behave reliably - in that I feel like I could reasonably deploy it and be confident it would continue to work as designed. It has been a nightmare of uninstalling and reinstalling, tweaking settings in configuration files and in flexbuilder project settings (and in code). I've tried on multiple machines, with a couple different versions of Coldfusion. But getting these two applications (Flex and Coldfusion) to talk to each other proved to be slightly more difficult than training my dog to chew with his mouth closed. It has been a huge disappointment, mostly because my hopes were so high based on the quality organization that Adobe is and the intelligence with which they usually deploy their products.
Alright, so now that that's off my chest, I didn't actually write this post just to complain. In trying to fix this problem, I researched dozens of blog posts, forum threads and articles, and found people everywhere that were having the same or similar problems I was, and frankly, they have all been surprisingly consistent in being considerate enough to post what they did to finally fix the problem. However, nowhere did I find a thorough explanation of WHY things weren't working, or how they're supposed to work.
The point
So, I thought I'd give my synopsis of what I've learned over the last month in the hopes that it will save someone else the trouble I went through. It really is everything we dreamed. It's just that the current iteration is a little...quirky
By the way, my development context is to have CFMX 7.0.2 (and sometimes Coldfusion 8 beta 2) installed on my workstation in developer mode, Eclipse installed independently and using the Flex Builder 2.0.1 plugin. I applied Hotfix 1 in all the hubub (build 159086), but it didn't seem to affect anything. I say this because this set-up represents the full scope of my experience with setting up Flex, so if you have a different webserver or have CF configured differently, it might change how these values interact with each other. Take it for what it's worth.
Flex Builder
You probably realize this already, but typically, Flex Builder 2 compiles your mxml file into a .swf file, as well as generating a bunch of html and javascript files, a couple of sub-directories, and another set of files for de-bugging. What might not be immediately obvious, is that you don't need all of that. Once your app is built and working correctly, all your webserver needs is the single .swf file that's generated and your supporting Coldfusion code. (ok, there may be instances where multiple .swf files are generated for a bigger project, but the point is...) you don't need all the html and javascript files if you just want to embed the .swf into your existing web page. That said, there are decidedly some useful stuff in those scripts, especially the whole browser-history management bit. The HTML templates folder is useless to you and should not be included in the production environment.
Flex2Gateway
The first thing you should understand is the special url "http://www.yourdomain.com/flex2gateway". If anything goes wrong, you'll notice this url (or some derivative) in the error code, and if you're like me, will quizically scratch your head (don't bother scratching unquizically, it doesn't work nearly as well) and try to see if Flexbuilder created a flex2gateway folder or created a CFMapping equivalent. Neither of these is true. The /flex2gateway/ directory is one of those "magical" directories that just exists, much like /flash/gateway/ did for flash remoting. Actually it's exactly like that. Both of these are established in the [coldfusion_root]\wwwroot\WEB-INF\web.xml file. I'm still not sure exactly how the CF engine tells the webserver that it cares about the things in this file, but if you peruse the file a bit, you'll catch on to the fact that these <servlet-mapping> tags are patterns that the CF engine looks for, including .cfm, .cfc, .cfml, etc. So my guess is that CF is just watching the URLs for incoming http requests, and if it sees the /flex2gateway/ pattern, it says to IIS (or whatever your wevserver is), "Uh that's mine. I'll take care of it."
To test this, call the url in a browser (http://www.yourdomain.com/flex2gateway). If everything is working correctly, you will get a blank white screen. If you don't - say you get a 404 error or something, things are not working correctly. The first thing to check in this case is your site in IIS. You need to have the JRunScripts virtual directory in every site that you're going to want to use RemoteObject on. During the ColdFusion install process, it gives you the option to install it for "All websites in IIS". This is slightly misleading, because what it actually does is install it for all sites that are currently in IIS. i.e. if you later add another site, it will not have the necessary virtual directories installed. Reinstalling CF will do it, or you can manually create the virtual directory.
To recreate the virtual directory, first go to a site that already has it. Right-click on the JRunScripts and choose Properties. On the Virtual Directory tab, note or copy the "Local Path" value. It will probably be something like [ColdfusionRoot]\runtime\lib\wsconfig\1 Though it might be different, depending on your installation of CF. Then, close that window go back to the site (in the IIS console) you're trying to run Flex on, right click and choose New>>Virtual Directory... Set the Alias to "JRunScripts" and the Directory to the value from the other site. Click Finish. Now you'll notice that a new Virtual Directory exists in your website, but it has a different icon than the one you copied. I'm not sure that actually makes a difference, but if it bugs you, you can right-click the new Virtual Directory, choose Properties, then, on the Virtual Directory Tab, under Application Settings, next to the Application Name, click the "Remove" button. Click Ok.
If this still doesn't work, the only thing I know to do is to uninstall and reinstall ColdFusion. If you have the option to install LiveCycle dataservices during the Coldfusion install, you might want to opt out of that. This creates a different services-config.xml file, and it screwed things up for me.
So, as I understand it, when your .swf file makes a call against a <mx:RemoteObject> method, the Flash player makes a special request to our special http://www.yourdomain.com/flex2gateway url, and sends a special packet of information in the special AMF protocol (feel special yet?). It then gets a response (also in AMF), interprets it, and passes the results back to your resultHandler. So needless to say, if your /flex2gateway isn't working, you're pretty much up Sheet Creek.
Services-config.xml
This little file, located in your [Coldfusion root]\wwwroot\WEB-INF\flex directory, has been the bane of many a would-be Flex-Coldfusion developer. As far as I can tell, this file has some important information in it that helps Flex Builder compile the .swf correctly, or - more accurately - to compile the .swf, including data that will help it at run-time. The single piece of data that is the thorn in the paw is <channels><channel-definition id="my-cfamf"><endpoint> - specifically - the "uri" or "url" attribute. This is what Flex Builder uses to know where your /flex2gateway url is. Note that, in it's default state, it has variables inserted for server.name, server.port, and context.root. Many have found that hard-coding their url in here has helped solve their problems, especially when working on a split development/production environment. Mine is currently working with the variables left in, but at one point, I did have to hard-code the url to get it to work. Why did it start working later? I have no idea. At least one of these properties is set in your project properties, but we'll go over that later.
You can, however, have multiple copies of your services-config.xml file. In Flex Builder, right-click on your Flex project, choose properties, then click on "Flex Compiler," you'll see an "Additional compiler arguments" text box. If you have Flex Builder 2.0 or later, I believe, this will already have something filled in for you, probably -services "[Coldfusion Root]\wwwroot\WEB-INF\flex\services-config.xml" If you want to use a different services-config file, you can put in the path to it here. That way you can have a different services-config file per project, if you really want to.
Alternatively, you can actually specify the endpoint (your special flex2gateway url) right in your mxml code if you want. It goes in as an attribute (named "endpoint", oddly enough) to your <mx:RemoteObject> tag. However, note that if you do change your endpoint - either in services-config.xml or in your code - and it now differs from the domain that you'll be calling the .swf from, you will need to make changes to your crossdomain.xml file (see below)
Project Properties
In Flex Builder itself, there are a number of project properties that are both cryptic in meaning, and essential to your app running correctly. That's not a particularly ideal combination, but hopefully I can clear them up a little. These are set up when you first create your project, but don't worry. Most can be edited once the project is created with no problem. Just right-click on the project in the Navigator view and click Properties. You should see four Flex-related categories on the left. If you don't see those categories, I'd guess you're either using eclilpse without having installed Flex Builder plugin, or, when you created the project, you created it as something else besides a Flex project. If you did that, it's probably technically possible to adjust the project properties appropriately, but honestly, it's probably a whole lot easier to just delete the project (without deleing the files if you like) and recreate it as a Flex project.
- Flex Applications
- The only real thing of interest here is to make sure the correct file is set as default - i.e. the one you want to run when the app is called.
- Flex Build Path
- Unless you're sure you know what you're doing (I don't) leave the stuff up top alone (Source path and Library path). I think Source path allows you to put .mxml and .as files in other directories on your hard drive (e.g. to organize them better), and then link them into this project for compiling. I have no idea whatsoever what Library path is for, but it's back there hiding behind Source path like a kid brother or something, so I think it's safe to leave it alone.
- Main Source folder: This points to where Flex builder should look for the source code it's going to compile. By default, this value is blank and - unless you're doing something weird like putting your source code somewhere other than in the project folder - it's safe to leave it that way.
- Output folder: Points to where Flex Builder will place the compiled .swf files, as well as the surrounding html and javascript files. This defaults to bin (or possibly flex depending on your version of Flex Builder). For the most part, you probably ought to be able to leave it thus, but if, for example, you want to have FB put it directly into your web root, you could do that here. Note though, that if you do change it, the change needs to be reflected in the "output folder URL" field as well. NOTE: you may get a warning from Flex Builder that "The output folder is not a subfolder of the server root." Don't worry about it. we'll talk about server root in a minute, but there's no reason your output folder needs to be in the server root. Your app can compile and run fine without meeting that condition.
- Output folder URL: This is the URL Flex Builder is going to be opening in a browser when you click "Run" (it is over-rideable. see Run Configuration below). It has no other meaning than that, and doesn't affect your app running correctly. If you set this wrong, and you click "Run" FB will open the wrong url, and you'll get an unexpected result - probably a 404. However, if you then type in the correct url in the address bar of your browser, everything will work fine.
- Flex Compiler
- Additional compiler arguments: make sure the -services flag points to the full physical path to the services-config.xml file you want to use for this project. If you don't know what it should be set to, or don't care because you're over-riding it in your code, just use the default: -services "[Coldfusion Root]\wwwroot\WEB-INF\flex\services-config.xml"
- Flex Server (got root?)
- Root Folder: By far the most frustratingly mysterious field, ("Root Folder" - What's that supposed to mean?) in practical terms, it translates to "Set this to [Coldfusion Root]\wwwroot". This field needs to point to the folder on your hard drive that contains the WEB-INF directory. I'm not sure why that needs to be here at all, as it seems to point to where on your machine coldFusion is installed, which should'nt be necessary just to develop and compile the app. It's apparently required, though. I also don't see why you would need to set it on a per-project basis. I guess if you had multiple instances of Coldfusion installed, you might want one project to run on a different CF instance, but for most of us, this will never change. In any case, if you put it to anything that doesn't have the WEB-INF directory, FB will scream at you and call you bad names, and - as a side note - won't let you go any further, so just put in a path to your Coldfusion root.
- Root URL: As far as I can tell, this has no meaning whatsoever. I've purposely put in false information, and it does not error. Nor does the errant data show up anywhere in the produced files. The only consequences seem to be that if you put in something that conflicts with "Context Root", FB will complain, but will still let you compile. Docs say this should point to the root url of your flex app. I suppose it's possible this value is accessible in the flex app itself.
- Context Root: This value is particularly weird. Apparently, it's supposed to refer to the root of the Flex app, relative to the web site root. So if your app was at http://yourdomain.com/someDir/someotherdir/flex/myFlexApp.htm, the context root would be "someDir/someotherdir/flex". HOWEVER, if you follow this line of thinking and put that value in this field, it will most certainly break your code. The cause is your services-config file. At least in its default configuration, it inserts the value you put in this field into the magic flex2gateway url that it uses. Since, as far as I can tell, that magic url always needs to be http://yourdomain.com/flex2gateway, anything you put in this field will cause that call to fail, and in your flex app you'll get something like Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Status 405:. Now, if you have modified your services-config file and hard-coded the url, or if you've removed the reference to Context.root, it will work fine, but that's just because it's over-riding the code. The only way I've found to make these two work without even a complaint from FB is to put the root url of your website in "Root URL" and leave the "Context Root" field blank.
Trivia note: These properties are actually reflected in the .flexProperties file located in your project root. You could theoretically change them in there directly. I don't recommend it, however, because it bypasses some built-in error checking and... well, basically... you could screw stuff up.
Run Configuration:
The Run Configuration is something that's very important to being able to run your flex app, but I've seen surprisingly little documentation or even mention about it from Adobe. Essentially, the Run Configuration determines what happens when you click the "Run" button in Flex Builder. Your app is compiled each time you save (if you have automatic build turned on) or when you manually click Build Project or one of its brothers. But even if it compiled succesfully, and has no syntax, run-time, or logic errors at all, you may not see it when you click run, unless the Run configuration is set up correctly. To enter this area, click Run>>Run (Not Run History, Run As, Run last Launched, or Run to Line, just Run...). Click on the plus sign next to "Flex Application" to expand it and see the configurations inside. If you do not have a plus sign next to "Flex Application", that means you don't have any. Click the "New launch configuration" button above to create one. You can name it anything you like, but you should probably name it after your project, as you'll have to create multiple configurations if you have multiple projects (or you'll have to edit your configuration each time you switch projects - your choice). However, beyond that, this screen is fairly simple and straight-forward.
- Name: this is only meaningful to you. Put whatever will identify the run configuration to you. You're going to need one of these for each project, so if probably makes the most sense to name it after the project you're running.
- Project: Identify which project you want to run with this configuration.
- Application file: Choose the .mxml application file that you want to run as the main app. Note that this ignores which one is the "default." If you only have one application file in your project (which is actually best practice anyway), you won't have any choice here.
- Use Defaults:If this is checked, you'll see the urls populated with the value from Output Folder URL in Project Properties Flex Build Path screen, plus the name of the application file above with the extension changed to .html. You'll also see the debug version with "-debug" appended to the file name. These urls are the ones that will get launched in the default browser when you click "Run". So if these are wrong, even if your application is fine, you'll get a 404 or some other unexpected result. If you uncheck the box, you can hard-code the urls to use. (So, if you were of a devious bent, and your fellow flex coder didn't understand this mechanism well, you could sneak onto his machine, uncheck the box and hard-code the url to an inappropriate website, then sit back and enjoy his consternation every time he tried to test his Flex project.)
Blank Blue-gray screens
Occasionally, people (myself included) run into a problem where the Flex app compiles without errors, the Run Configuration launches the browser to the right url, and the Flash Player does indeed fire up, but the app is not displayed. All you get is the default blue-gray screen with no content. If you right-click, you'll see a grayed-out message saying "Movie not loaded..." The surface reason for this is that when you install coldFusion, it registers itself for .swf files, but it's not letting this one through. I have no idea why. It may very well be a valid security restriction of some sort, but I can't figure out what it is, and I can't find any documentation on it, so here's the hack. Go into IIS and bring up the affected website's properties page (this will be different depending on what version of IIS you have) On the "Home Directory" tab, click the "Configuration" button. On the popup, scroll down to the S's and you'll see that the .swf extension is registered to the Coldfusion dll. If you don't, then I don't know what's causing the blue-screens for you, sorry. If you do have it, highlight it and click remove, and confirm the decision. You may need to restart the World Wide Web Publishing service, but you may not. I can't remember, honestly.
Crossdomain.xml
If you've done any searching at all on your problem, you've probably come across this already, as this aspect is very well documented. But it's another possible problem in the Flex-Coldfusion integration, so I'm going to mention it anyway. If your .swf file is going to be on one domain, and your CFCs are going to sit on another (your magic flex2gateway directory), you will need a crossdomain.xml file. This file tells the flash player that your domain has permission to get data from another domain. It's a very simple format (see Adobe's documentation), and the file goes right in the website root of the domain where the cfcs are and must list the domain where the .swf resides. If you get these backwards it won't work, and you'll get a security error in the Flash player.
Disclaimer: This data is provided as-is based on my experience, not based on official documentation from Adobe, nor through any consultation with an authoritative answer whatsoever. Your mileage may vary
Disclaimer #2: I reserve the right to come back and update/ammend/correct this post as I learn more, so don't get too comfy with it, especially if it contains errors, just leave a comment and let me know.
So what was the actual problem?
As for the "vast" majority who have no problems, I think a Google search on 'flex "Channel.Connect.Failed " ' will speak differently.
It should be noted however, that my problems all stemmed from trying to work with the <mx:RemoteObject> component. Using simple client-side flex or even the <mx:HttpService> compnoent was truly easy and intuitive. In fact, using the Remote Object was intuitive as well. It just didn't work.
I too could not be more disappointed in all the trouble I'm having getting Flex to consume a simple CFC-based web service. This should just work, but it just doesn't. Flex seems to work much better consuming .NET services, go figure.
http://www.jebshouse.com/wordletter.php?l=H
[Flex2Gateway Issue]
I ran across this issue about a year ago and was able to resolve it by doing the following.
Internet Information Server 5.x - 6.x
- Right Click on the Site --> Properties
- Click the Home Directory Tab
- Click Configuration
- Add a wildcard application mapping to the jrun_iis6_wildcard.dll (usually in <cf_root>\lib\wsconfig\<instance>\jrun_iis6_wildcard.dll
The same is true for IIS 7 except you have to add a Wild Card Mapping as the HTTP Handler and that is it!
The wild card handler is necessary so that Cold Fusion server knows when a request is made to a symbolic name i.e. Flex2Gateway.
Thanks,
Saul
Cheers, Mike.