CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jay Kimble -- The Dev Theologian

Philosophizing about the .Net religion

Atlas Play: Using the AutoCompleteExtender with a Page Method (cleaner/simple version)

[out of date post... this deals with MS Atlas CTP... which has been change drastically and is now MS Ajax Extensions]

Ok, the code in yesterday’s post was ugly! I’ve come up with a simpler example that doesn’t use reflection, but it does require maintaining a switch…case/select…case.

I’m introducing a new helper class to do our heavy lifting, and an interface for calling back to the page (I can still can come up better solutions than this one… but it’s workable for me for now [so if you want to tweak it some more… knock yourself out… I’m done after this one])

Here’s the interface that the page will implement-

public interface IAtlasAutoCompletePage
{
  
string[] ExecuteMethod(string MethodName, string prefixText, int count);
}

One method that let’s us tell the page which Autocomplete function we want to call and the normal Autocomplete parameters.  I imagine you could probably build a method using delegates and a custom object/generic collection that would do away with both this interface and the implementation’s case statement (that will be up to you).

Here’s a page’s codebehind (BTW, the see yesterday’s post for the html part of the page).

using System;
using System.Collections.Generic;
using System.Data;
using System.Configuration;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Services;
using Microsoft.Web.Script.Serialization;

public partial class AutoCompleteWithNoWS : System.Web.UI.Page, IAtlasAutoCompletePage
{
  
protected void Page_Load(object sender, EventArgs e)
   {
     
try
     
{
        
AtlasAutoCompleteHelper helpme = new AtlasAutoCompleteHelper(this);
      } 
     
catch
     
{
        
// Do something with the exception... 
        
// use the logger of your choice is a good recommendation
     
}
   }

   [WebMethod(true)]
  
public string[] GetAutoComplete(string prefixText, int count)
   {
     
string[] result;
     
if (prefixText.Length > 8) return new string[0];
      result =
new string[4];
      result[0] = prefixText +
"AAAAAAAA";
      result[1] = prefixText +
"DDDDDDDD";
      result[2] = prefixText +
"MMMMMMMM";
      result[3] = prefixText +
"VVVVVVVV";
     
return result;
   }

   public string[] ExecuteMethod(string MethodName, string prefixText, int count)
   {
     
switch (MethodName)
      {
        
case "GetAutoComplete":
           
return GetAutoComplete(prefixText, count);
        
default:
           
return new string[0];
      }
   }
}

Really there is only a couple changes from yesterday’s code.  First of all the Page Load simply instantiates the AtlasAutoCompleteHelper class passing an instance of itself.  I could have built this as a Base class, but I’ve found that the inheritance tree can be a pain (especially when you don’t want to always include a feature… this means you have 2 different page inheritance trees and you have make sure that changes in one tree get populated in the other, etc… it can be a pain)

Here’s the AtlasAutoCompleteHelper class (which does the heavy lifting for us)

using System;
using System.Collections.Generic;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.Web.Script.Serialization;

/// <summary>
///
Summary description for AtlasAutoCompleteHelper
/// </summary>
public class AtlasAutoCompleteHelper
{
   private Page page;

  
public AtlasAutoCompleteHelper(Page pg)
   {
      page = pg;
     
if (isAutoCompleteWSCall())
      {
         CallPageAutoComplete();
      }
   }

   private void CallPageAutoComplete()
   {
     
string output = "";
     
try
     
{
        
byte[] buffer = new byte[page.Request.InputStream.Length];
         page.Request.InputStream.Read(buffer, 0, buffer.Length);
        
string inputString = new string(System.Text.UTF8Encoding.UTF8.GetChars(buffer));
        
Dictionary<string, object> ParamsFromJS =
             Microsoft.Web.Script.Serialization.
JavaScriptObjectDeserializer.Deserialize(inputString) 
                 
as Dictionary<string, object>;

         IAtlasAutoCompletePage pg = page as IAtlasAutoCompletePage;
         output =
JavaScriptObjectSerializer.Serialize(
              
pg.ExecuteMethod(page.Request.QueryString["mn"].ToString(), 
                     ParamsFromJS[
"prefixText"] as string , (int)ParamsFromJS["count"]));

      }
     
finally
     
{
         page.Response.Clear();
         page.Response.ContentType =
"application/json";
         page.Response.Write(output);
         page.Response.End();   
     
}
   }

 

   private bool isAutoCompleteWSCall()
   {
     
return (page.Request.QueryString["mn"] != null && 
              
page.Request.ServerVariables["HTTP_CONTENT_TYPE"] == "application/json");
   }
}

 So there are 2 methods plus an intializer in our helper class.    The isAutoCompleteWSCall determines whether this is a call to an AutoComplete function.  It checks for the mn querystring and JSON content.. NOTE: postback is not checked… AutoComplete calls aren’t postbacks!  Remember this! That means that your form fields have NOT been transferred back… Code your AutoComplete functions accordingly!  [yes, I’m shouting on purpose…. I want to save you some pain… BTW, Session is available if you need some state mechanism <wink />]

The initializer stores the page instance in a private variable, calls the isAutoCompleteWSCall to check to see if this is an Autocomplete call.  If it is then the CallPageAutoComplete method is called.

CallPageAutoComplete reads the JSON string from the inputStream of the Request object, and deserialize the string into a Generic dictionary (just like yesterday).  The generic dictionary object is used to populate the parameters for the call to the page’s IAtlasAutoCompletePage interface’s ExecuteMethod.  The result is re-serialized to a JSON string, sent back to the page (after setting the content type to JSON), and then the request is stopped.

There are probably a couple enhancements you could make to this example (I’m done with it as previously mentioned).  You might want to create a class that takes a method name and a delegate), and pass a generic collection of these to the helper function instead of using the interface.  This would probably be a little cleaner, but you will either need to use Reflection or maintain a list of functions to call. 

BTW, one of the benefits that I can see to this version (although I have yet to try) is that you don’t need to use the WebMethods Attribute… although I would recommend it.  I suspect that this example will be unneeded in future versions of Atlas.

 

Technorati Tags: , ,  


Published May 03 2006, 10:08 AM by Jay Kimble
Filed under: , ,

Check out Devlicio.us!

Our Sponsors

Free Tech Publications

This Blog

Syndication

News

CodeBetter.Com Home
Current Threat level
Terror Alert Level