Sunday, May 17, 2009

Auto Complete Example Project

I've written an ASP.Net project that shows how to configure the Auto Complete Extender(ACE), get back the text and the ID, and pull data to show in a details view. If this is your first time using the ACE, pay special attention to the web service files and the javascript in the default.aspx page.

To run this project you'll need Visual Web Developer 2008 Express, MS SQL Express 2008, and the Adventure Works demo database(AdventureWorksDB.msi).

In addition to the ACE I also used an ASP Update Panel and some basic Linq To SQL.

You can download my example project here. You'll need to set the correct connection string in the web.config file to connect to your copy of the AdventureWorks database. If you need help with connection strings, try this site.

Saturday, May 16, 2009

More AutoComplete

I have been getting a lot of hits on the Google Search Appliance Auto Complete post. I thought I would add a few more notes concerning the Auto Complete control in the ajax.net toolkit. Let's say you have a long list of items in a drop down list. Wouldn't it be better to filter that list based on what the user types? Yeah, of course! That's why we have that functionality all over the web now. The only probelm is that the Auto Complete control isn't as easy to use as the other controls in the Ajax control toolkit.. For instance:

  1. You have to write a web service to handle the back in call to the data source. So if all of your data is in an MS SQL database, or Access, or XML, you have to write the query for that and put it in a web service and tag it with a WebMethod attribute. Read more about web services here.
  2. The webservice that the Auto Complete calls can have any name but it must have the following paramter signature: Public Function GetItemName(ByVal prefixText As String, ByVal count As Integer) As String(). The first variable must be a string and it has to be called prefixText. The second one must be called count and it has to be an Integer. Read more about the Auto Complete extender here.
  3. One final thing you need to know about the Auto Complete extender is that most of the examples you'll find online show how to get back the text that the user selected, but they don't show you how to get back the ID. Let's say you have a dropdown list of car parts. There could be thousands of them. The user types in a few letters, sees the part, arrows down to it and hits enter. What you need now in order to do look ups in your related tables is the ID of that item, not the text itself. How do you get that? Inside my webMethod function I do something like this: tempResult.Add(AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem(itemname), itemID))
    In this example tempResult is List( Of String). By using this CreateAutoCompleteItem function I can create an item that the Auto Complete Extender knows should be split into a text value to display and an ID value that will actually be used. Now, the return type has to be a string array, so the last line of my function is "Return tempResult.toArray()". I like working with generic lists but you could just as easliy dimension a string array with the size based on the count paramter.
  4. Now, how do I get the value back from the ajax call? In the markup for the AutoComplete Extender, you need to specify a javascript function to be called after the user selects an item. Something like this: OnClientItemSelected="showItem". The showItem function will look something like this:
    function ShowItem( source, eventArgs ) {
    alert( " Key : "+ eventArgs.get_text() +" Value : "+eventArgs.get_value());
    }
  5. What's that? You don't want the value in a javascript alert, you want to assign it to an ASP.net control, like an asp:HiddenField or something like that? Then do a getElementById('hiddencontrolID').value = eventArgs.get_value(); somewhere in your javascript function.
  6. Now you are probably going to ask...what if it's in a User Control and there are lots of them on the page and I don't know what the ID is going to be for each asp:Hidden control? That's an answer for another blog post. If this one generates lots of hits I'll write it up.

Thursday, February 12, 2009

Auto Complete on the Google Search Appliance

At my job we have an .aspx page that displays search results from a Google Search Appliance. Nothing too fancy. The page passes the query, gets the XML results from the GSA, we pair that with an XSLT and sha-zam, search results. It was brought to my attention that some one higher up the chain wanted to know if we could have that "cool google suggest drop down thing" on our search page. Google has it. Amazon has it. Dang near every text box on FaceBook has it. Why don't we? Seveal people told me that there must be a way to enable it, because it's a GSA and Google runs it on their site. Now, I'm as guilty as the next guy when it comes to assuming how hard/easy something is going to be. I'm not pointing fingers. As with most things, there's a little more to it.

First off, the Ajax toolkit from Microsoft has an auto complete extender. It's great for running against SQL tables, or XML files or just about any data source. You can get back the ID of the record that the user selected and really make things snazzy. The question is, how do I use a GSA as a data source?

The GSA does return results in XML, but it doesn't do wild card queries. You can't do a search for "hea*" and get back head, hearing, heart and things like that. You get Dr.Hea and some mis-spellings and that's it. I did some looking on the Google Code site and found a "Search as you Type" project that seemed to do just what I wanted. It said in the documentation that you could turn any text box into a Google suggest box. It was written in PHP but I figured I could download it and convert the page to .Net. Most of it was in javascript files anyway so no biggie. Except that the page doesn't connect to a GSA. It has a pipe delimited text file that it uses as the demo source for the drop down. I looked through the readme.txt looking for some way to magically refernce the GSA. Nothing. What I had found was a Google Base code project that did the same thing as the ajax toolkit from Microsoft. I was right back where I started.

I fumed for a little bit. I drummed my fingers on my desk. I went back to Google's site and looked over their page source and javascript files. Then, as I was taking a swig of Red Bull, I realized what Google was doing. They weren't running against their index either.

Google is fast but not so fast that they can ajax call from your browser back to their index and back to your browser with search results each time you press a key (Update 7/12/2011:  Actually, they are that fast now.  Most of my speculations about Google in this post are obsolete). They have been in the search business for quite a while so there is no doubt that they know the top 1,000 search terms for words that start with each letter of the alphabet. The top 1000 As, the top 1000 Bs and so forth. Google had compiled a list of the Top 26,000 key words (something like that, I'm gusessing) and that's what they are running against when they do the Google suggest ajax call.. That's why when you do an obscure search it doesn't show anything but when you hit "search" you get results.

Now, back to my problem. It's not a problem anymore. I can run a report against our GSA, get back the top 10,000 or so search results, filter out the trash, and have everything I need in a nice and tidy XML document. I can put it in a SQL table or leave it in XML. I'll b able to sort it either way. Now I can use the ajax toolkit Auto Compete extender and in a short amount of time I have the same functionality as Google Suggest for our GSA. Only I'll be using .Net.

I'll post the code and link to the search page when I'm done. Shouldn't be long (will I ever learn to stop saying that).

Wednesday, February 11, 2009

Debugging and Windows Service in VB.Net

Perhaps this is helpful, perhaps not.  I've spent the last 45 min looking over various blog posts and .Net sites trying to find an easy way to debug an NT service.  I kept coming across, install the serivce, start it, attached  a debugger to a process...etc.  I know there is an easy way to do it because I've used it several years ago in .Net 1.1.  I gave up searching and went looking through old source code and found it. 'Tis below:


'****Modified by JWear on 4/12/2006****

Private Sub New()
If Debugger.IsAttached = True Then
' debug code: allows the process to run as a non-service
' will kick off the service start point, but never kill it.
' shut down the debugger to exit
'Open this page for help ' 'http://www.codeproject.com/dotnet/DebugWinServices.asp
Dim service As New YourService
Dim tempargs() As String
service.OnStart(tempargs)
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite)
Else
'Original Code Below
ServicesToRun = New System.ServiceProcess.ServiceBase() {New YourService}


System.ServiceProcess.ServiceBase.Run(ServicesToRun)
'Original Code Above
End If
'**************

End Sub

I left the page where I got it in the comments, a hat tip to the original site. The page is no longer available.