Another extender which make me believe harder…
That ATLAS programming should be centered around the client, not the server side! Well, today I received a mail asking if I could take a look at a small sample which tried to use a regular AutoCompleteExtender (yack! Hey, look how AutoCompleteBehavior sounds much nicer than that previous name) which should invoke a remote web service. It’s true that I haven’t been playing much with ATLAS lately, but since I do like it, I’ve taken some time off to study some of its components (specially the client side). I knew that this should work because, internally, the AutoCompleteBehavior (which, as you might guess, is responsible for getting everything working on the client side) uses the Sys.Net.ServiceMethod class to invoke the web service. Due to that, we should be able to invoke local or remote web services. In fact, if you look at the AutoCompletebehavior class, you’ll note that the remote method is invoked through this line:
Sys.Net.ServiceMethod.invoke(_serviceURL, _serviceMethod, _appURL,
{ prefixText : _currentPrefix, count: _completionSetCount },
_onMethodComplete, null, null, null,
[ this, text ]);
As I said, I received a cool simple sample written by Rob Thijssen with two projects: a web service project and an ATLAS project with a simple page that tried to invoke the remote web service with this code:
<atlas:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server">
<atlas:AutoCompleteProperties Enabled="true"
MinimumPrefixLength="1" TargetControlID="TextBox1"
ServicePath=http://localhost:3007/AutoCompleteService/Service.asmx
ServiceMethod="GetNamesByPrefix" />
</atlas:AutoCompleteExtender>
According to Rob, it didn’t work. And yes, he was right…it didn’t work. Running the sample would return something like this:
The server method 'GetNamesByPrefix' failed with the following error:A web request made using the iframe executor failed. Make sure that the app's web.config registers iframecall.axd in its .
Wtf? It was then that I looked again at the AutoCompleteProperties and noticed that it’s missing a very important property…yes, it doesn’t have an appURL property!!! If you look at the AutoCompleteBehavior, you’ll find a property with that name which is passed to the ServiceMethod.invoke method. Well, you see, the team just decided that that property wasn’t important…in fact, it is important! You see, that property is used to define the app url that is hosting the web service and if you don’t set it, the server side iframe handler won’t be able to correctly process the remote web service call (and yes, it’s ok not to set it if the service is on the same app as the page that’s calling it). So, the 1st lesson is: always use the client side behaviors when possible.
Unfortunately, I’m not seeing most guys doing that (mostly due to the way ATLAS is being presented by MS). So, until the team fixes this, we’ll have to resort to a small workaround. Yes, you can extend the AutoCompleteProperties class, but it’s too hot to write server code (it really is – 33ºC at 23:15 is hot), so we’ll just have to resort to a client side approach to solve this.
What we need to do is inject client code that correctly sets up the AutoCompletebehavior used on the client side. Doing that is easily accomplished by this code:
<script type="text/javascript">
Sys.Application.load.add( handle ); //handle the load event so that xml-script has been processed
function handle( object, e ) {
var ref = $object("<%= TextBox1.ClientID %>" );
ref.get_behaviors()[0].set_appURL( "http://localhost:3007/AutoCompleteService/" );
}
</script>
In the previous code, we just get a reference to the AutoCompleteBehavior and explicitly set its appURL property to the correct value (this works in this case because the textbox only has one behavior added to it). That’s all that needs to be done to use the current server side extenders (yack!) to call a remote web service from the AutoCompleteBehavior.
Btw: guys (ie, ATLAS team), the next time you decide to wrap a client behavior with a server extender, please do wrap all the properties…
[update: I've forgot to mention that you might need to enable ATLAS on the remote web site that is hosting the service since the client will call will the iframecall.axd handler of that site]