The problem with conjuring tricks is that they lose practically all their glamour once you find out how they are done. It’s very cool to see David Blaine walk down the street, do a few passes over his hand, and resurrect a fly which proceeds to flee. It’s rather disappointing to do a google search and discover that in order to prepare for this trick, the first requirement is that you freeze a fly.
My trick is to make an autocomplete extender from the Ajax Control Toolkit call a WCF service instead of an asmx service. For this recipe, I assume that you are already familiar with the autocomplete extender, and that you are using Visual Studio 2008. I warn you in advance — my trick disappoints. It is so trivially easy that, once the technique spreads, it is very unlikely to impress your colleagues at work, much less get you a date with a supermodel.
Start by creating a new web project called AutocompleteWCF. Add a reference to the AjaxControlToolkit.dll. Open up the default aspx page that is generated with your project, and add the following code to:
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<asp:TextBox runat="server" ID="myTextBox" Width="300" autocomplete="off" />
<ajaxToolkit:AutoCompleteExtender
runat="server"
BehaviorID="AutoCompleteEx"
ID="autoComplete1"
TargetControlID="myTextBox"
ServicePath="Autocomplete.svc"
ServiceMethod="GetCompletionList"
MinimumPrefixLength="0"
CompletionInterval="1000"
EnableCaching="true">
</ajaxToolkit:AutoCompleteExtender>
</div>
</form>
This is the standard demo code that is shipped with the Ajax Control Toolkit Sample Website. I’ve simplified it a bit by removing the animations. The only significant change I’ve made is to change the ServicePath from Autocomplete.asmx to Autocomplete.svc, the latter being the extension for a WCF service.
The next step is to create our service and add a GetCompletionList operation to it. The easiest way to do this is to go to Add | New Item and just select the Ajax-enabled WCF Service item template, but this would be so easy that it is hardly worth doing.
Instead, create a new WCF Service using the WCF Service Item Template and call it Autocomplete.svc. Visual Studio will automatically generate a service interface for you. Delete the interface. We don’t need it. (To be more specific, I don’t know how to get this to work with an interface, so I’m just going to ignore that it is possible.)
Again, I am going to rip off the ACT sample app and just borrow the code from their webservice and place it in our WCF service. The WCF service class (Autocomplete.svc.cs) will look like this:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Autocomplete
{
[OperationContract]
public string[] GetCompletionList(string prefixText, int count)
{
if (count == 0)
{
count = 10;
}
if (prefixText.Equals("xyz"))
{
return new string[0];
}
Random random = new Random();
List<string> items = new List<string>(count);
for (int i = 0; i < count; i++)
{
char c1 = (char)random.Next(65, 90);
char c2 = (char)random.Next(97, 122);
char c3 = (char)random.Next(97, 122);
items.Add(prefixText + c1 + c2 + c3);
}
return items.ToArray();
}
A few things worth noting:
1. Autocomplete does not implement the IAutocomplete Interface. Even though this is generated automatically, with the WCF Service item template, you should remove it.
2. The service contract has a blank Namespace explicitly declared.
3. The ASPNetCompatibilityRequirements attribute must be added to our class.
This takes care of the code that calls the WCF service, as well as the service itself. We now have rig up the web.config file. If you’ve been working with WCF for any length of time, then you know that this is where the problems usually occur. Fortunately, the configuration is fairly simple. You need to set up an endpoint behavior for your service that enables web scripting (much the way asmx web services must be decorated with the ScriptService attribute in order to be called from client-script). You also will need to turn AspNetCompatibilityEanbled on for the hosting environment.
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="AjaxBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="AutocompleteWCF.Autocomplete">
<endpoint address="" behaviorConfiguration="AjaxBehavior" binding="webHttpBinding" contract="AutocompleteWCF.Autocomplete"/>
</service>
</services>
</system.serviceModel>
And that is all you need to do make the AutoComplete Extender work with a WCF service instead of an asmx web service. I told you it would be unimpressive.
Of course, using a WCF service for Ajax has all the limitations that using an asmx file for Ajax did. First of all, you can’t call a service that is in a different domain than the page which hosts your client-code. This is a security feature, to prevent malicious code from redirecting your harmless javascript to something nasty on the world wide web.
Second, you can’t call just any service from your client-side code. The service must be explicitly marked as something that can be called from client code. In asmx web services, we used ScriptService for this. In WCF services, we similarly use EnableWebScript binding property.
Now I feel like I’ve wasted your time, so here’s a YouTube video of David Blaine to make up for it. And remember, David Blaine is to Chris Angel what Daisy Duke was to Alexis Carrington. It’s an existential thing, and at some point, you’ve just got to pick sides and stay put in a way that will determine who you are for the rest of your life.
Are you a David Blaine/Daisy Duke kind of person or are you a Chris Angel/Alexis Carrington sort? Do some soul searching and please let me know what you learn about yourself.