NOTE: To clarify, I am referring to remote calls used for both local AJAX requests as well as any public API calls that can be made (including those made by remote servers or clients).
I love ColdFusion components; I think they add a tremendous amount of value to the organization and cohesion of application features. In fact, I am hoping to learn how to use them in much more powerful ways. But, the one feature of ColdFusion components that I've never really been sold on is the remote access method functionality. I understand that this feature makes publishing SOAP-based web services extremely easy; but, outside of SOAP, do remote method calls actually add any value to an application?
Currently, when I need to make remote calls to my application, I simply call my front controller with the appropriate action value. As a matter of habit, I tend to put "api" before my API-based actions:
My front controller then routes the request through my API work flow which uses a JSON-based template rather than my standard page template. See, when you abstract out page requests, you can see that a JSON response and an HTML response are just different types of template rendering (which I think is what ColdBox does with it's render data method?). In doing so, my API calls naturally get hooked into all aspects of my framework including security. But, even more awesome is that by using the front controller, my unified API response and error handling (I always return a 200 on my API responses) can all be done in one place during the API routing.
This all works quite nicely and has provided no points of friction in development. So, I ask myself, what benefit would I have to switching to remote method calls for my API (not including SOAP publishing)? To be honest, I can't really think of any benefits, but I can think of some definite drawbacks:
- I have the overhead of instantiating a new CFC instance for every single CFC-based API call.
- I generally have to break encapsulation with a remote CFC (calling service objects via the APPLICATION scope or other hard-coded factory).
- I have the very inelegant task of removing my OnRequest() application event handler when using remote CFCs.
- You might consider the remote CFC a "Man in the Middle" anti-pattern as it rarely does anything more than call other components.
- Wiring in error handling becomes slightly more complicated.
- Wiring in interceptors becomes slightly more complicated.
- Page requests become decentralized, breaking the front-controller protocol.
Some of these are not huge drawbacks, but they are drawbacks nonetheless. And, with any drawback, I have to ask myself, does the benefit of the new methodology outweigh the drawbacks associated with the shift? As I cannot conjure up any real benefits, I can't say that moving to a remote-CFC-based API would make any sense for me at this time (unless I wanted to publish SOAP web services). What do you all think?
Looking For A New Job?
- Full Stack Angular/Rails Engineer @ newly funded Health-IT startup at Dorsata
- Part-time remote DBA needed at Bridge
- Senior Developer Wanted for International Cloud Company at Giva, Inc.
- ColdFusion Developer - jQuery, PrimeUI, ORACLE DB at ComSpec International, Inc.
- Jr. ColdFusion Developer - Full Time / Telecommuting is ok. at InterCoastal Net Designs
I _must_ be misreading this. Are you asking if it makes sense to make remote calls to your own server to get data via CFCs? You can't be - as that would be silly.
Outside of that - wouldn't you only use remote calls when you have to? Like with Ajax? Or are you proposing that your Ajax calls go to CFMs that chain out to the business logic?
I'm truly lost here as to what you are asking. ;)
Yes, I am referring to AJAX-type calls. But also to any remote call that needs to be made such as a rest-based API service I might provide. I just don't see the benefit of using CFC-based remote calls over standard front-controller calls.
So, if I understand, you're asking if doing remote calls to many disparate CFCs makes sense?
Probably not the way you describe it, but what we do is have our front controller be a CFC. Then, you get all the benefits of the controller, centralized error handling, etc. with the CFC advantage of JSON, SOAP, XML or text returnFormats all for free.
That's an interesting idea. How does your index.cfm work? Does it simply turn around and call your CFC-based front controller:
#Controller.Execute( action-variable )#
I am not opposed to this - it could make a lot of sense.
Yep, it makes sense. I feel like an idiot now, but the blog post works a lot better for me now that I get your point. ;)
I've had the same question myself. I kind of feel like that if I'm using a framework for my application, it doesn't make sense to bypass it for remote calls. Why shouldn't the remote user use the same framework I designed for the local user? Yes they may have different security needs, different output needs, but at the end of the day they are still using the same application.
That being said, I'm not sure your list of reasons are that strong:
"I have the overhead of instantiating a new CFC instance for every single CFC-based API call."
I'm kinda with you on this on, but typically the remote CFC is the only CFC created, so it should be negligible.
"I generally have to break encapsulation with a remote CFC (calling service objects via the APPLICATION scope or other hard-coded factory)."
Encapsulation is important, but like all rules, is not meant to be 100% followed blindly. imho, this is a perfect example where it makes sense.
"I have the very inelegant task of removing my OnRequest() application event handler when using remote CFCs."
Hopefully CF9 will fix that. ;)
"You might consider the remote CFC a "Man in the Middle" anti-pattern as it rarely does anything more than call other components."
You could make the argument that it would allow for remote-specific security/logging/auditing, but I'd rather handle that in the framework. So I'm with you here.
"Wiring in error handling becomes slightly more complicated."
Well, error handling for Ajax can be complicated anyway. ;)
Good food for thought here, Ben.
Yeah, sorry about not being clear. I added a note to the top of the post for some clarity.
Granted, they are not *huge* issues; but, the question remains, are their benefits to it that outweigh *any* issues. Like you are saying, why not have the API request go through the same work flow that was designed FOR page requests.
This is interesting. We use access="remote" extensively within our application to publish our API to the outside world and really do find it a pretty efficient way of doing so, it gives me a nice self-documenting API which also allows me to publish complex objects with a high level of ease, we've used REST in the past but found using SOAP to be a little simpler, so long as you don't mind the overheads.
I do know what you mean about this middleman anti-pattern though, most of my API methods are just calling other underlying service objects and then spitting the data out agin, it is a little messy however this is certainly FAR simpler than having to roll my own SOAP/REST services for publishing the data publicly.
One thing I would like to see in cf9 would be the implementation of multiple access methods, if I could expose the methods on my standard service objects as access="public,remote" for instance, that would make life very easy!
That said, ColdSpring offers some nice Proxy generation methods for remote SOAP services which allows standard application service objects in the model, and selected methods within them to be published remotely, during our migration into MG:G we plan on using this to consolidate our physical service objects so it doesn't feel quite like an API of middle-men, Just the single service object and a little XML config which exposes them. :-)
@Robert - what would access="public,remote" do?
Hmm, Ray, I just did a little reading on access="remote" and think perhaps I've misunderstood it's use in the past, I was assuming that you couldn't invoke a 'remote' method locally without instantiating the object as a web service, is that correct? or can 'remote' methods be called in the same way as a 'public' method with the addition to being available through a web service also?
If the front end is a FLEX app, you will lose some significant benefits.
* Performance, particularly when returning sets of data from ColdFusion to Flex, is much better.
* Data exchange is more flexible: ColdFusion query objects can be sent directly to Flex without manual conversion.
* ColdFusion applications can use an event gateway to synchronize information about data changes in a Flex application.
A remote method can be called locally. It's like a public method with 'benefits'. ;)
I just did some testing on that and you're totally right! I'd for some reason assumed that the remote methods were not available locally without create the object as a web service! This eliminates the middle-man argument in my case then as I can simply access my standard service objects directly from remote clients! :-D
I guess this assumption was based off the ColdSpring remote proxy feature, I'd guessed that's what the remote proxy's were intended to do, however no knowing that I can access them locally, they seem somewhat redundant?
What's your take on that?
Disclaimer: I consider myself a newbie CS developer. Take this with a grain of salt.
As you know, CS is a huge benefit to helping create/maintain complex CFC definitions. So when CFC A needs an instance of B injected and B needs C and C needs X, etc, CS can REALLY help simplify this.
So given this, and given that CS can be used to help instantiate a CFC, it can also be useful when needing to expose these CFCs remotely. You could write your own code to say: "ColdSpring, I need X, give it to me so I can call a method on it." But the remote proxy feature simply makes this easier. It can cut that step out.
I probably did a horrible job here, but I hope it helps a bit.
Sure, I get the premise behind the dependency injection however I don't quite get why that's any different to just setting access="remote" in the cfc, you can still have ColdSpring serve it up for you, just means less XML. I don't know, perhaps you could tie different AOP advice to the remote proxy this way or something.
Iether way, I'm probably pulling this thread off-track a little ;-) thanks for the heads up on the remote methods being available locally though, that's helped a great deal!
Just setting the method to remote is not enough. How do you _init_ the CFC? This is where CS helps you. It knows how to get an instance of the CFC. So setting access="remote" would not be enough. Certainly if the CFC isnt under web root. So this feature of CS will let you simplify the process of having a properly initialized version of the CFC available under web root.
Ah I get you Ray, that does make sense! It's getting the late in the day for me ;-) little slow on the uptake, I do apologise!
In that case the remote proxies make a great deal of sense! :-)
No problem, and I hope that for those who know CS better, that I did not butcher it too much. That's my impression of the feature anyway.
Remote access CFC have very big benefits. First, they allow one to expose a method for consumption via AMF and SOAP in addition to JSON/AJAX. So on this point, there is no debate, since there is no way to expose a method as a web service or a Flex RemoteObject if it is not remote.
The second reason is that you can control what is open for remote consumption. ColdSpring will generate a Remote Proxy object for you, or you could write your own, but the point here is that you can make your underlying CFCs private (not in the web root) and only have the Remote Proxies be remotely accessible. Which has several advantages:
* You can exercise fine-grained control over which methods are available for remote access (which you can do manually or have ColdSpring do for you).
* You can easily add additional logic that is specific to remote consumption, such as QueryConvertForGrid for CFGRID usage, or for building arrays of value objects for use by Flex, etc. You can do this yourself, or again you can leverage the extremely powerful AOP capabilities of ColdSpring to do this. Which way you choose to do it doesn't affect the benefit this provides (though the ColdSpring AOP route is much more flexible and maintainable IMO).
So with this in mind, to look back at the issues you see with this Ben:
* Instantiating one CFC (the remote proxy) is causing such minimal overhead (nearly 0 ms) that it can essentially be ignored.
* The remote CFC is acting as a facade to your application model, so it is not breaking encapsulation to reference the application scope here any more than it is when you reference the session scope in a CFC or method that is encapsulating access to a user session.
* I don't use OnRequest myself, but this is a definite bug or unexpected behavior in CF, so I wouldn't use it as a reason here. And as Ray noted, this should be addressed in CF9.
* A Remote Proxy isn't a man in the middle because it almost always is doing more than simply forwarding method calls. But even if it were, this is actually what a Facade does.
* Wiring in interceptors (of which error handling is a subset) is part of what ColdSpring does, but even if you were doing it yourself, I don't really see why it would be more complicated here than in the original component?
* Remote page requests often *should* break the front-controller pattern, since there is no view involved (in SOAP or AMF for example, the view is managed by the consumer)
The AMF argument is a strong one there. Although I wonder if Adobe would ever considering providing support for generating AMF directly. Ie, <cfset res = toAMF(somedata)>.
Brian I think you're dead right! that all makes a world of sense to me. I hadn't thought through the full benefits to using the CS remote proxies, but when you look at the points you make there it becomes very clear what it brings to the table.
All excellent points.
I got thoroughly thrashed by Sean Corfield a few years back by suggesting something similar (a "remoting" view of some sort which runs through the same framework, whether it be AJAX, JSON, XML, etc) on the Fusebox list. (see: http://tech.groups.yahoo.com/group/fusebox5/message/2305)
We wanted to be able to use the substantial amount of work we already had established by taking advantage of the Fusebox features (such as plugins, pre-process, pre-fuse, post-process, etc), without having to rewrite big chunks of that for a separate data channel.
I agree with you Ben. Duplicating anything more than necessary is always a bad idea. If my chosen framework isn't going to make this feasible, then it's a problem with the framework. In fact we were already doing plenty of this at the time, and greatly enjoying the ability to introduce AJAX functionality with little additional overhead.
I wasn't going to try to challenge Sean on his own turf especially given how vehement his response - even though he completely failed to convince me of anything. We just continued successfully doing exactly this.
In our apps we have a JSON layout, an Excel layout, a Word layout, a PDF layout, etc (our default layout is actually XSLT, we generate XML in our view and transform it to HTML in the layout). The code can decide what layout makes the most sense for the purpose at hand.
Eric, glad to hear you didn't just blindly follow Sean's advice. I think too many people in the community just blindly accept what the 'big wigs' say w/o really thinking/digesting/considering the situation on their own. I know I've made that mistake myself. A huge part of becoming a better developer is being able to critically look at other's code. (imho)
@Gus, @Ray, @Brian,
Admittedly, I know very little about FLEX and FLEX/ColdFusion integration; as such, I assume that you are correct in your AMF statements. So, yes, if you are defining an API for consumption with AMF, then CFCs make sense. I also know nothing about RemoteObjects - I've never had to use them in my apps... but when I learn FLEX, perhaps that will change.
Regarding the security and granular control - to say that CFCs add more security features is based on an assumption that you would *not* have security with a standard front controller, which is hopefully not true :) The CF Framework provides ample space for all kinds of security and interceptor hooks.
Perhaps by using a framework like ColdSpring, you must use CFCs to leverage more of the aspects; but, I don't see any reason why similar behaviors cannot be build into a front-controller type work flow. In fact, I think it might be easier.
Regarding Facades and encapsulation, I am not a design patterns expert, so I must defer to you (Brian). However, I assumed that even in Facade, most dependencies would/should be injected using IoC. I stand corrected.
As far as the OnRequest() with CFC's this is actually not a bug. As you can see in my previous post:
... there is no inherent problem with using CFCs an OnRequest(). The *issue* is when people try to CFInclude the CFC path. This, inclusion makes no sense (how can one include a CFC file??), and is why, I believe, ColdFusion throws an error.
As far as a Facade vs. Man in the middle anti-pattern, I am not sure about this. A Facade is meant to simplify a set of features, is it not? Calling a CFC method vs. invoking a URL with an action variable are about as similar as you can get. The Facade isn't really "simplifying" anything from a public point of view?
As far as error handling goes, perhaps there is a much better way to handle it than I have found. To get error handling to work with a remote CFC, I have had to beef up the OnError() handler in the Application.cfc:
To me, this is significantly more complicated than using a CFTry / CFCatch block around the total API work flow within the front controller.
Regarding "views" with remote calls - I think it really comes down to what you consider a view?? With a standard view, is it really a "View" ... or are you simply return text-data with the MimeType "text/html"? When you consider a "View" in this manner, then isn't JSON really just text data with the MimeType, "text/json" (or text/x-json)?
So, as far as all the FLEX integration and the SOAP and the AMF, it sounds like clearly, without a doubt remote CFCs, DO add serious value there.
But, for all other remote calls, I don't see the value. Now, sure, you could consider that using CFCs builds in flexibility for later integration; but, I guess it's just a tradeoff on what you think you will use.
... plus, there's nothing to say that remote CFCs cannot be added later when / if ever needed. Then, the can simply turn around and call the front-controller-based methods, I assume, or something to that effect.
Glad to see you are using this technique with success :)
"... there is no inherent problem with using CFCs an OnRequest(). The *issue* is when people try to CFInclude the CFC path. This, inclusion makes no sense (how can one include a CFC file??), and is why, I believe, ColdFusion throws an error."
I'd argue this. Logically we can say, 'look at onrequest - obviously it makes sense that it would break an CFC call'. But the flip side is that every day this 'feature' is tripping developers up. It may not be a bug, but it is a bad design decision in my opinion. Ben, how often do you get asked about this? I know I get emails almost weekly. :)
@Ray: agreed. It's exacerbated by the livedocs not covering this point, and the examples not testing for CFC's. If LiveDocs warned you of the problem and showed you how to work around it, then I'd probably side with Ben.
"Regarding the security and granular control - to say that CFCs add more security features is based on an assumption that you would *not* have security with a standard front controller, which is hopefully not true"
It is true, I don't implement security in the front controller for exactly this reason. It ties your security model to only your HTML-based front-controller application. I believe security should be handled within the model layer. You can catch security exceptions in the controller, and you can check security states in the view if you need to determine what to display, but that should be all IMO.
You're right about the remote facade. You certainly *can* have dependencies injected if you wish, but in most cases the method call is simply forwarded to the underlying target CFC, with AOP interceptors running before and/or after the method call (including error handling
Regarding your question about what is a "view", I wrote a blog entry a while back on a similar subject which might shed some light on my position (and that applies to data requests such as SOAP and AMF as well): http://www.briankotek.com/blog/index.cfm/2007/7/25/AJAX-Data-Requests-vs-AJAX-Content-Requests
Since AJAX data reqeusts fall into the same category as AMF and SOAP access (the only difference is the format of the returned data as JSON vs. binary vs. XML), it makes sense to allow the application to handle any of them in an agnostic manner. In other words, if you structure things so that the app doesn't care whether which kind of consumer is asking for data (be it JSON, AMF, or SOAP), it means that your application can handle all of them.
I will agree that it definitely trips people up. I guess the question is - what can be done to stop this that makes sense? I am not sure I would even know what to do. The only think that I can think of is that CFC-based calls would ignore the OnRequest() method; but, then we have to make sure that we don't put any additional logic in the method. Or, ColdFusion could simply *not* throw an error if you try to CFInclude a CFC.
Neither of these feels all that clean to me. So, yes, it's a feature that definitely trips people up (including myself!), but I am not sure what the right work around would be. It sounds like CF9 is fixing this, but I admittedly have not been very involved in the beta :(
If you put security in your front controller, I don't think it ties your security to your HTML controller. If the front controller can serve up any view including HTML and JSON and XML and whatever-based, then the security is handled by the controller which will act as an intermediary to every public interface and your service layer.
Now, it is no secret that I am NOT a great architect and OO for me is an uphill battle (Your presentation was quite good by the way - thanks for kicking off cf.Objective() on a high note!!), so take this all with a grain of salt.
I will definitely check out your blog post on data-based requests.
I think you nailed it on the head - a CFC request should simply ignore onRequest.
Ahh, ok cool :)
I took a look at your blog post. I wanted to reply here (just to keep the whole conversation in context). I am not sure that there really is a delineation between HTML-based and DATA-based requests. And, the more complex the AJAX handling gets, the fuzzier line this becomes.
Take, for example, a request that grabs some HTML data and inserts it into the page. This simple grab-and-insert might be considered *just* an HTML viewlet grab.
But, what happens if I take that HTML response, and before I insert it, I use jQuery to bind event handlers and listeners. Then, once bound, I insert it into the page.
Is it just HTML at that point? Or was is XML-data that was rendered on the client?
XML is a data trasporation format, just as JSON is. And, since XHTML is a sub-set of XML, can it not also be easily thought of as a data transportation model?
Heck, what if you developed a text-only client that could take HTML and use some sort of XSLT to render it text-only. Then, you would have XHTML as data in the purest sense.
And then there's something like RSS feeds. My RSS feed is XML (data), but it has a CSS file defined in it which the browser users to render the XML in a more "pretty" fashion. At this point, is the RSS a data request or a view request?
My gut would say "data", but only because it's XML based and that is what I'm trained to think. But, the more I think about how the data is requested, the more I realize that this separation of request times seems somewhat arbitrary.
When I ventured into my first project using the built in cfajaxproxy in CF8, I found the mechanism for directly connecting to the object from the client not as cool as it first looked.
First, my CFCs are never stand alone CFC's that's contain all the data it needs to be self sufficient. Like my data sources are application scope variables, and it seemed as though using cfajaxproxy would instantiate it's own stand alone CFC outside the application.
At first this was frustrating as I really want to leverage the very easy looking ajax calls to CFCs...
So instead I just went with 1 cfm page that works as a director of calls, and a little bit of client side JS to call the server.
So no I see no benefit from moving to some ajax connector remote access method for CFCs other than the automated web services.
Especially when just using a CFM script to handle AJAX requests is still great, easy to understand and super maintainable.
This has been a very interesting discussion.
In the big application I've been working on for the past year I decided to go the CFAjaxProxy route.
I have developed the site in ModelGlue 2 and it didn't really sit right with me to think about calling the framework for every Ajax call required. It just felt like the overhead would be overkill.
Now the way I've done it is a little long winded (I'm sure it could be simplified) but has worked pretty well so far:
I basically have a single CFC within the webroot called ajaxProxy.cfc. This is what CFAjaxProxy makes use of. It's a simple component which, using the Coldspring bean factory in the application scope, requests the RemoteFacade CFC from within the model (stored outside of the webroot).
The RemoteFacade while still quite simple has all of the beans I need for remote access injected in automagically. It then has a set of methods which calls other methods in the model. As Brian mentioned, I do some special handling in this facade although I tend to write methods into the various service layers which handle security based on the functionality required (e.g getMessagesByUser - default enforcement of only returning messages for the logged in user with the RemoteFacade only requesting data for that user).
This makes it nice and easy to add Ajax specific methods as required. I know having the Ajax proxy and the RemoteFacade may seem like useless duplication but it made sense to me to have a simple lightweight CFC in the webroot that only needs to grab the RemoteFacade, rather than having lots of other beans injected into it and providing logic that really should be in the model. The RemoteFacade is nicely placed where I feel it should be.
I know this could potentially be improved using Coldsprings remote proxy functionality but for now I feel this works pretty well while maintaining encapsulation.
So in summary, for my application using a CFC for remote access made a lot of sense. Running it through MG would have been a lot messier and I feel would have potentially adversely affected performance. This way just feels cleaner.
If you remote CFC proxy is circumventing the Model Glue framework, then what functionality is your MG framework providing during standard page calls?
Since my name was invoked...
HTML frameworks (like Fusebox etc) are designed to take an HTTP GET/POST request of name/value pairs and return a text string - using HTML but it can be XML or JSON if you want to do the conversion manually.
You can't use that approach with Flex/Flash (AMF) or SOAP clients. For those, you must use CFCs with remote methods.
Guess what tho'? If you use CFCs with remote methods, you can serve not only AMF and SOAP but also JSON *automatically* and, if you feel the need, WDDX automatically.
If you build your application as a set of services (exposed as CFCs, remotely and locally), then you can slap any UI in front of them, be it Flex, SOAP, AJAX or plain ol' HTML.
What I "thrashed" people for was trying to circumvent good design (building services) and instead wanting to shoehorn AMF and SOAP remoting into an HTML framework.
These days, Model-Glue and ColdBox have built in support for remoting via AMF, SOAP and JSON using a CFC-based API into the framework. It's a way to get a Flex (or SOAP) app up and running quickly if your logic is too closely tied into your framework. But both Joe and Luis will tell you this is not the best way to build such an app, merely a convenient way to migrate from HTML to Flex.
Anyone who builds a Flex UI first can easily build an HTML UI using a framework that talks to the existing CFC-based service logic they already have (for the Flex app). The reverse is not true.
Also to Brian's point, security should be in the service layer, not the controller layer, if you ever expect to expose parts of your app thru non-HTML clients.
The MG framework takes care of everything else which isn't served via Ajax. So it builds all my pages and handles exposing the model to the frontend.
With my Ajax approach I'm simply communicating with the model in a different, more lightweight way. I can still make use of the same model when rendering my HTML pages via MG.
I don't really see a major problem with this approach and it seems to work pretty well in the development of a pretty big and complex site. At least so far. :)
I guess what I was getting at was that if the remote CFC is "light weight," then what is the MG framework doing that's so "beefy." And, I guess the follow question would be - does the MG page request have to be so beefy (I am not very familiar with the MG framework).
Right, I guess it comes down to the fact that adding non-HTML interfaces is easier when you pre-architect remote CFCs.
@Sean: I guess I have a hard time seeing why the framework cares what sort of data it is serving up. As far as the framework should be concerned, data is data whether it's HTML data, XML, binary, whatever. If it cares what it's outputting past offering certain optional target-specific enhancements, then it's probably doing something wrong.
As I mentioned, we offer more layouts than binding directly to CFC's permits, including PDF, Excel, Word, XML, etc. It can be consumed by absolutely any client no matter what format is required, and if a new client comes along that needs a format not currently supported it's simply a matter of adding this as a new layout option and enabling it in the situations for which it makes sense.
Ah I see what you mean and a very good question.
It's probably good to clarify what data is retrieved via my proxy and remote facade. I'm using it for fairly small data requests - deleting a message, posting a message / question etc. Some requests don't actually return any data.
A MG request, while still nice and fast does go through a range of processes. Controller is instantiated, model beans retrieved and placed in event scope, event passed to the view (or multiple views) which are combined and rendered.
This all seemed a bit of overkill, especially when simply asking the model to delete a message for example. Why go through the whole framework and rendering a view that does nothing? Or one which simply outputs some JSON. At least that was my rationale.
I'm still using the same nicely encapsulated model - just accessing it in a more direct and efficient way.
Where I use Ajax to dynamically refresh a content area I do use MG as I feel this fits more into what it does best and I like to keep the layout template driven and defined in the MG XML.
@JamesAllen: Actually the controller is instantiated on the first load. As you wouldn't normally return beans to an Ajax app, your remote call would probably return just a serialized query (or struct) from a service object, which would _also_ be already instantiated.
Yeah when I wrote that I knew I should have mentioned that once instantiated the controller will sit in the application scope. It was more to illustrate the number of processes involved in an MG request.
Your second point is a good one. As my model is all Coldspring controlled, my light weight Ajax requests via my RemoteFacade are made even more efficient as all the beans are already instantiated.
If I'm grabbing a Transfer bean, I'll usually do what your saying and return a struct with the data I need in it or a serialised query which is automatically handled by the access='remote' in the proxy.
One of my ajax functions is polled every 30 seconds to obtain user data (latest message received, new notifications etc). To run this through a MG request would be overkill I feel.
@Steve It's just a shell of functionality right now but I am working on a FuseboxContext singleton for remote CFC calls in a Fusebox applications. It will be created on request by Fusebox remotely called CFCs can then get the instance and execute stuff in the context of Fusebox, so you could do something like FuseboxContext.getInstance().do("circuit.fuseaction"). I felt this was an easy way to leverage Fusebox and still do what you need to do in remote CFC calls, I feel the proxy pattern was appropriate for Fusebox users. Combine that with the patch Sean provided for CS integration and you'll have a nice way of leveraging CFC remoting and Fusebox.
It's in the nightly builds (well what is finished anyway, http://tinyurl.com/fuseboxBER) you might check it out, I think my release notes have a short blip about it if not I plan to play with it more this week so I should have something more soon. In all honesty though it is a very very simple CFC in the core you could look at it and know what it does in about 30 seconds...
I am a bit late but I always wondered why all of the cf frameworks never made the request cycle a modular and distinct process. IMHO, Today's framework should not be married to HTML. (I still love you HTML but you can't have me!)
Having a swappable request handler system would allow any competent developer to easily tailor a request handler component for his/her specific needs.
HTML App uses: HTMLRequestHandler.cfc,
AJAX App uses: AJAXRequesthandler.cfc,
Flex App uses: FlexRequesthandler.cfc,
AIR App uses: AIRRequesthandler.cfc,
Briefly how I envision this working...
Break the request mechanism down into three methods (receiver, processor and responder) within a request handler component which is then registered in the application's configuration file. A huge centralized application can have various User Interfaces, each configured to use a particular request handler while invoking the same event handlers.
The job of the Receiver() method is to capture, format and hand the event data (event action and args) over to the processor.
The job of the Processor() method is to push the event data through the framework machinery and provide a raw structure of the resulting data (messages, errors, views, event data) for the responder.
The job of the Responder() method is to organize the already processed data and send the results back to the Requester (Client App) in the predefined format (Gimme JSON, WDDX or WAZZOO).
I know I digressed greatly but since so many of us use frameworks, I am sure many would agree that it is so much nicer (depending on your requirements) to utilize the framework's solid infrastructure to remote some of your application's existing procedures.
I would love to hear more thoughts on this because it's one of those things that I really dislike about current frameworks and would greatly appreciate learning from others with similar encounters and solutions...
I am not too familiar with any one framework, but I think some of them might operate along these lines, at least, once you get past the initial receiver. But, like I said, I cannot really speak to this specifically.
Yes, you are correct but it is not done in a modular fashion. Frameworks like Model-Glue, Mach-II and ColdBox merges the Form and URL scope directly which is absolutely perfect when working in the realm of HTML but Flex, Air or AJAX will require a bit of a hackish approach to process a request through the framework since the request handler's mechanism is tightly coupled to the framework.
Basically what I am saying, is if I am going to use a Flex App to send requests through a framework's remote proxy, I should be able to predefine the appropriate request handler which is efficiently designed to receive a flex request, process it and respond respectively. Since Form and URL merging is not necessary in this instance, all data sent from the Flex App is merged directly into the Event object simply because my custom FlexRequestHandler.cfc offers this simple luxury.
I think I see what you're saying; however, I am not sure that I understand how merging the URL and FORM scopes actually causes any complications?
I don't have any issues with Merging Form and URL data within the context of an HTML based application request but I do see a flaw in design if you are doing the same thing for a Flex based application.
Do you mean "flaw" as in it doesn't work? Or you mean flaw in that it just is unnecessary?
I am not too familiar with the frameworks, again, but I think the standardization helps the controller / service layer interaction from having to worry about differences.
For example, when you make a WSDL-based web service call, there is NO FORM scope available to use. But, rather than the internals of the system having to worry about that - it all gets simply packaged into some sort of event. If anything, the "Event" de-couples the underlying service from any particular invoking model?
(flaw in that it just is unnecessary)
Sorry, I should of been more clear.
I don't want you to think that I am making a great deal over the Form scope thing. It was just a small part of my reasoning behind this. Logically in my mind I thought it made perfect sense to encapsulate the request handling functionality inside a laser focused component that is designed to address a particular request model appropriately, instead of the one shoe fits all and a few dozen <if> statements later to pull it off.
HTML application supporting SES URLs - HTMLSESRequestHandler.
HTML application - HTMLRequestHandler
AJAX application - AJAXRequestHandler (returns pure JSON)
No restrictions or unwanted bulk.
Maybe I am being a bit picky.
I don't think you are being too picky. I think it makes sense to have different Controllers (HTML / Remote) have different entry points into the application. I was actually discussing this topic at length over the weekend.
What a discussion. Right off the bat I saw you were looking at remote access wrong. I use remote access to CFCs to just return data to the calling site or accept data from a sending site. They have no need or desire to use my framework or anything else, they just want to tap in remotely to mess with my data.
This is very big when coming to affiliate sales. I can send them an XML file containing the info on a requested product and they then format it anyway they want. Or I use it to capture and store affiliate sales data.
Yes, if the remote caller is just going to mimic some of your site, then a remote cfc is redundant. Just let them come to your site.
@Don: as you start to get into more complicated sites, you start to get into CFC's which are not stand-alone. A single service-level CFC may require interactions with as many as 15-20 other CFC's.
Some of these CFC's are extremely expensive to instantiate so you don't want to just create them on the fly as a disposable object. For example, a CFC whose purpose is to interact with the product catalog may load 5,000 Product CFC's into memory in its init() method so we can avoid the database hits and overhead of doing this work at runtime for the user (as you're probably aware, CFC instantiation is unfortunately a very expensive operation).
At the same time you may have security and authentication controls, remote data sources of your own, database health checks (we have some features where the SLA of our data is narrower than ours, so those features automatically become unavailable when the source of our data is offline - but we handle it gracefully), etc.
Some of this stuff takes a lot of setup work that should only really be done one time for the lifetime of your application. To tap into that and also be able to take advantage of just-in-time object instantiation, it makes sense to serve all your data through the same framework regardless of whether it's html data, json data, xml data, or whatever. No matter what format you're targeting, the output is data.
Personally I have a hard time seeing why some people think there's something special about HTML output vs some other format for your data. The alternate suggestion is to build all of this setup and optimization work twice, once for your HTML offering, and a second time sans framework for your 'data' offering (where they narrowly define data to exclude HTML for some reason).
If I'm going to build the same functionality without a framework, then why bother also building it in the framework?
Oh, now we will have to disagree. BTW I am working on an application that is HUGE. For the gubment. It was originally written in CF 4.5 and now I'm upgrading it to CF8. Quite a leap. urg.
The original coder (not a programmer by any stretch) did a lot of what you are talking about ... running huge queries on the server and then storing them so later he could just tap into that stored data. This means the first time that query is run it takes forever to run. Much like instantiating a CFC like what you are talking about.
HOWEVER, as my Oracle guru co-worker told me "it is better to run these huge queries on the $10 million db server than on the $500k ColdFusion server". We can spit out xml or html even from the stored procedure. Not only that, but Oracle automatically stores the queries so if you are running the same one over and over, it automatically taps into the stored info.
The time savings doing the heavy db work on the db server is amazing.
I've done it your way too on store fronts (instantiate the cfcs for the catalog ahead of time). Now I'm speed testing against doing all the db grunt work on MS SQL server with it returning very nice XML that I can transform. Oooooooooooo. Much faster.
Moral of the story is let the db do the db work even if you think making tons of calls will slow you down.
Of course if the data rarely changes and you only run the query once a day (possible if you are grabbing a catalog) then loading the xml into an application variable may be the best way to go.
Then again, I come from old school (real old) of keep it simple. I see these cfc round robins that could be simplified vastly.
It's less about the database call and more about component instantiation. If you go with a purely OO model, you have one instance of a Product CFC for every product being displayed on the screen. If you have 300 products on the screen that starts to hurt. If you have 300 products on the screen for 300 simultaneous visitors that starts to hurt a whole lot. Much better to pay that price exactly one time when the application is first starting up than to pay it repeatedly for every page view.
For one app, one of the database servers we had to talk to was in Australia while the main application was in the US. There was a 500 ms overhead per query even if was just SELECT * FROM DUAL. We could also query 6000 records and it would come back in about 550ms. Very high latency, very high throughput. It was much less expensive to do one big query than many small queries. You run into the same sort of phenomenon when you're talking to certain data sources such as SAP.
I'm not saying this is the appropriate approach for every application, but to say that caching never has benefits would be absurd. We switched to this model specifically because it was killing our performance when we were doing one-off queries. This is a widely recognized enough phenomenon that there was even a session on it at CFUnited this year called, "What to do when OO fails you in ColdFusion."
Anyway, it's beside my point. The point is that sometimes CFC's aren't stand alone, or sometimes CFC's have an unusually high cost for creation. The products thing was merely an example of what might cause that. Sometimes there are very good reasons to tie into functionality you already built with a framework, but expose it as data intended to be consumed remotely. For the life of me, I can't see why a framework should care whether it's serving HTML or XML or JSON or anything else, and therefore I see no reason not to run it through the same framework, and be able to take advantage of the features the framework brings to traditional web development.
Ahhhh. There is the problem. You don't NEED a CFC for each product. You need 1 cfc that handles ALL products.
This is what I mean by keeping it simple.
For a store you basically need a global cfc for the catalog. It handles everything dealing with products. If a person clicks on a product, you are passing the idx to the cfc to do the work. If you have a seperate cfc instantiated for each product, you are wasting memory and time. Redundancy like this will kill you. So you make 1 call to the db say at midnight every day or when there is a massive update that brings the required data into an application variable as a query.
This data should be the very MINIMUM needed to display it. Anything else can be a quick call to the db for more info. About all you might have to make calls to the db for on a routine basis is if you are showing inventory levels with the products.
Another cfc you need is the shopping cart. Now that one has to be 1 per customer. So that could get huge if you are a very popular site like say Amazon. So once again, you keep what that cfc does to a minimum. If you have upsells and crosssells and recommendations and blah blah it can be a complex cfc making complex db calls or calls to the stored query.
I can't think of a single reason to have a cfc for each product. Maybe I'm missing something there.
One CFC for all products may be using objects, but it's not object oriented programming, it's procedural programming using objects as a namespace. (Sidenote, ColdFusion doesn't support namespaces)
There's nothing wrong with that, it's just not OOP.
And it's all still irrelevant to the point I was making: Sometimes you have complex applications where you have CFC's that have interdependencies or high cost to creation and so it makes sense to cache it. You should be able to use your framework to facilitate this stuff.
BUT the real purpose of webservices is actually just to provide data. Not everything else that goes along with a website or framework. Like if I want to list your products on my site, I make a call to your webservice to get the data. I don't want all your framework stuff getting involved. If I want that, I will frame your website or some such.
I guess us old people still like to keep it simple.
BUT my original reason for coming here is to find out why a call to a remote cfc won't recognize a method. There are 2 methods in the cfc but only 1 works remotely the other one returns an error saying the cfc can't be found. I can navigate to it and it works fine. But try to call that method and it says it can't be found. Exposing the cfc shows it is there.
I put it in a different cfc by itself and it works. So is there a limit of 1 for remote methods in a cfc?
a) I think you're using a different definition of "framework" then Ben - really has nothing to do with the "what you see" part of the website, per se.
b) I know there's no limit of one remote method - we have many CFCs with many remote methods.
How are you trying to call the two methods?
Nope, there is no limit to the # of methods you can put in a CFC, remote or not. Did you remember access="remote"?
As @Edward said, the Framework has nothing to do with how the public user interacts with the web service. I would guess that every API uses a framework to some degree.
Are you using WSDL? If so, you might have a cached WSDL file (which was created when there was only one method in the CFC). In that case, you can refresh the WSDL with the refreshwsdl="true" attribute (I think) in the CFInvoke tag.
Or if you are just viewing the WSDL in your browser, refresh it in the CF Admin.
1) I'm only recommending that data be sent back, none of the visual markup. XML, JSON, etc. The framework I refer to here is purely the server-side functionality that establishes your runtime environment when your CFC's aren't stand-alone.
2) Make sure the CFC you're invoking is the one you think you're invoking. Maybe try making a conspicuous change in the method you can access remotely, and make sure that's the one that's being executed. Had a bear of a time tracking something like that down some time back; there was an old CFC that was left over in the ear\war folder from a previous debugging effort that had a name collision with the CFC I thought I was invoking.
Does anyone know how of a way to tell the access type used to call a remote method, (public or remote)
since they can be called within a cfc as just a function (public) or from a http reqeust (remote) i.e. ajax,
is there a property that can be read within the method?
I know I am late to this thread, but...
IMNHO, I believe this entire conversation is the result of our atrocious web technology. I've felt (ever since I got into it) that it is a hodgepodge of patches/fixes/enhancements/etc. that are confusing at the best and downright detrimental at the worst.
It seems to me that our browsers are being asked to do things they weren't designed to do. The the HTML request/response model is inadequate for what we are trying to do. etc. etc. etc.
What I think we should do is junk the entire current browser model and switch to a simpler, easier, model.
1) the new "browser" should accept "form objects" from the server. These "form objects" would be written in a (possibly new) language designed to accomplish two things: create great UIs & communicate efficiently with the server.
2) the server side should be written in an event-driven manner, which accepts these communications from the client and acts upon them.
3) there should be no difference between coding a desktop app and a web app. The only difference should be that for a desktop app, the "client" and "server" are on the same physical machine.
In this model, the client handles all UI events, including user inputs and data presentation.
The server handles the persistence and organization of the data being forwarded to the client.
This concept is a high-level extension of the Interface concept from Java/.Net. As long as both server and client adhere to the "Interface" they can work together. This "Interface" must be known by both the server developers and the client developers. If that "Interface" is modified, the IDEs for both sides with throw red-squiggles.
Just my never-so-humble opinion!!