Converting to ASP.NET Ajax Beta 2 (A Guide for the Perplexed)


There are a few good guides already on the internet that provide an overview of what is required to convert your Atlas CTP projects to Ajax Extensions.  This guide will probably not add anything new, but will hopefully consolidate some of the advice already provided, as well as offer a few pointers alluded to by others but not explained.  In other words, this is the guide I wish I had before I began my own conversion project.


1. The first step is to download install the Ajax Extensions beta 2 and the Ajax Futures (value added-) November CTP.  One problem I have heard of occurred when an associate somehow failed to remove his beta 1 dlls, and had various mysterious errors due to using the wrong version. 


2. Create a new Ajax Extensions project. This should provide you with the correct library references and the correct web configuration file.  Here are the minimum configuration settings needed for an ASP.Net Ajax website to work:



</configuration>


     <system.web>
     <pages>
     <controls>
            <add tagPrefix=”asp” namespace=”Microsoft.Web.UI” assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
           <add tagPrefix=”asp” namespace=”Microsoft.Web.UI.Controls” assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″/>
           <add tagPrefix=”asp” namespace=”Microsoft.Web.Preview.UI” assembly=”Microsoft.Web.Preview”/>
     </controls>


     <compilation debug=”true”>
          <assemblies>
                <add assembly=”Microsoft.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35″/>
          </assemblies>
     </compilation>

</configuration>

 


You also need to make sure that you have a reference to the Microsoft.Web.Extensions dll as well as to the Microsoft.Web.Preview dll, if you intend to use features such as drag and drop or glitz. Both of these dlls should be registered in the GAC, although it wasn’t for me.  To make sure it was available in the GAC, I had to add a new registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\ASP.NET AJAX 1.0.61025  with a default value indicating the location of the ASP.Net Ajax dlls: c:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025″


On a side note, there seems to currently be some ambiguity over whether the Microsoft.Web.Extensions dll can or cannot simply be placed in your bin folder rather than placed in the GAC.  It seems to work, even though the official documentation says it should not.


 


3. Wherever you used to use the shortcut “$” as a shorthand for “document.getElementsById“, you will now need to use “$get” .  I usually need to go through my Atlas code three or four times before I catch every intance of this and make the appropriate replacement.


 


4. Sys.Application.findControl(“myControl”) is now simplified to $find(“myControl”).


 


5. Wherever you used to use this.control.element, you now will use this.get_element().


 


6. The “atlas:” namespace has been replaced with the “asp:” namespace, so go through your code and make the appropriate replacements.  For example,



<atlas:ScriptManager ID=”ScriptManager1″ runat=”server”/>


is now



<asp:ScriptManager ID=”ScriptManager1″ runat=”server”/>


 


7. Script References have changed.  The ScriptName attribute is now just the Name attribute.  The files that used to make up the optional ajax scripts are now broken out differently, and so if you need to use the dragdrop script file or the glitz script file, you now will also need to include PreviewScript javascript file.  This:



 


<atlas:ScriptManager ID=”ScriptManager1″ runat=”server”>
     <Scripts>
          <atlas:ScriptReference ScriptName=”AtlasUIDragDrop” />
          <atlas:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
     </Scripts>
</atlas:ScriptManager>


is now this:



<asp:ScriptManager ID=”ScriptManager1″ runat=”server”>
     <Scripts>
          <asp:ScriptReference Assembly=”Microsoft.Web.Preview” Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewScript.js” />
          <asp:ScriptReference Assembly=”Microsoft.Web.Preview” Name=”Microsoft.Web.Resources.ScriptLibrary.PreviewDragDrop.js” />
          <asp:ScriptReference Path=”scriptLibrary/DropZoneBehavior.js” />
     </Scripts>
</asp:ScriptManager>


 


8. Namespaces have changed, and you may need to hunt around to find your classes.  For instance, Sys.UI.IDragSource is now Sys.Preview.UI.IDragSource, and for the most part you can probably get away with replacing all your Sys.UI namespaces with Sys.Preview.UI.  On the other hand, Sys.UI.Behavior has stayed where it is, so this is not always going to be the case.  The method setLoctation has also shifted namespaces.  It used to be found in Sys.UI.  It is now in Sys.UI.DomElement.


 


9. Xml Scripting change: Xml scripting, which allows you to use javascript in a declarative manner, is now part of the Value Added CTP.  As I understand it, the Value Added CTP, also known as Ajax Futures, includes lots of stuff originally included in the Atlas CTP but deemed to be of lower priority than the core Ajax Extensions features.  In order to meet a tough deadline, these have been set aside for now.  The Ajax Toolkit, in turn, is heavily dependent on these value added features, since the toolkit components tend to leverage the common javascript libraries such as Glitz much more than the specifically Ajax features provided with the core release.  The syntax for adding custom behaviors using Xml Scripting has changed, while the syntax for built in behaviors is the same.  An Xml Scripting region used to look like this:



 


<script type=”text/xml-script”>
   <page xmlns:script=”http://schemas.microsoft.com/xml-script/2005″>
      <components>
         <control id=”dropZone”>
           <behaviors>
               <DropZoneBehavior/>
           </behaviors>
         </control>
         <control id=”draggableDiv”>
           <behaviors>
             <floatingBehavior handle=”handleBar” />
           </behaviors>
         </control>
      </components>
  


Now it looks like this:


<script type=”text/xml-script”>
   <page xmlns:script=”http://schemas.microsoft.com/xml-script/2005″
xmlns:fooNamespace=”Custom.UI”>
      <components>
        <control id=”dropZone”>
          <behaviors>
            <fooNamespace:DropZoneBehavior/>
          </behaviors>
        </control>
      <control id=”draggableDiv”>
         <behaviors>
              <floatingBehavior handle=”handleBar” />
         </behaviors>
      </control>
    </components>
  </page>
</script>


Note: The AspNet AJAX CTP to Beta Whitepaper has a slightly different syntax, but this appears to be a typo, and the one I have provided above is the correct grammar.


10.  Adding behaviors using javascript has changed.  The biggest thing is that you no longer explicitly have to convert a DOM object to an ASP.Net Ajax object, as this is now done beneath the covers.  The get_behaviors().add(…) method has also been retired.  For my particular conversion, this code:



function addFloatingBehavior(ctrl, ctrlHandle){
     var floatingBehavior = new Sys.UI.FloatingBehavior();
     floatingBehavior.set_handle(ctrlHandle);
     var dragItem = new Sys.UI.Control(ctrl);
     dragItem.get_behaviors().add(floatingBehavior);
     floatingBehavior.initialize();
     }



got shortened to this:



function addFloatingBehavior(ctrl, ctrlHandle){
     var floatingBehavior = new Sys.Preview.UI.FloatingBehavior(ctrl);
     floatingBehavior.set_handle(ctrlHandle);
     floatingBehavior.initialize();
     }


This can in turn be shortened even further with the $create super function: 



function addFloatingBehavior(ctrl, ctrlHandle){


   $create(Sys.Preview.UI.FloatingBehavior, {‘handle’: ctrlHandle}, null, null, ctrl);


}


 


11.  Closures and Prototypes:


You ought to convert javascript classes written as closures to classes written as prototypes.  Basically, instead of having private members, properties and methods all in the same place (called, it turns out, “closures”), they are now separated out into an initial definition that includes the members, and then a definition of the prototype that includes the various methods and properties, which are in turn rewritten using a slightly different grammar.  Here is a reasonably good overview of what the prototype object is used for.  Bertand LeRoy‘s two posts on closures and prototypes is also a good resource.


12. You basically follow the following steps to mechanically rewrite a closure as a prototype. First, change all your private variable declarations into public member declarations.  For instance, the following declaration:



var i = 0;


should now be:



this.i = 0;


 


Consolidate all of your members at the top and then place a close bracket after them to close your class definition.


13.  Start the first line of code to define your prototype.  For instance, in my dropzonebehavior class, I replaced this:



 Custom.UI.DropZoneBehavior = function() {
     Custom.UI.DropZoneBehavior.initializeBase(this);
     initialize: function(){
          Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘initialize’);
          // Register ourselves as a drop target.
          Sys.Preview.UI.DragDropManager.registerDropTarget(this);
          }


}


with this:



Custom.UI.DropZoneBehavior = function() {
       Custom.UI.DropZoneBehavior.initializeBase(this);
}



Custom.UI.DropZoneBehavior.prototype = {
     initialize: function(){
             Custom.UI.DropZoneBehavior.callBaseMethod(this, ‘initialize’);
            // Register ourselves as a drop target.
            Sys.Preview.UI.DragDropManager.registerDropTarget(this); 
            }


}


simply by adding these two lines:



}



Custom.UI.DropZoneBehavior.prototype = {


 


14. Throughout the rest of the prototype definition, refer to your variables as members by adding


this.

in front of all of them.


 


15. Interfaces have changed.  The bahavior class, which did not used to take a parameter, now does:



Custom.UI.FloatingBehavior = function(value) {
    Custom.UI.FloatingBehavior.initializeBase(this,[value]);

}

 


16. Properties and methods are written differently in the prototype definition than they were in closures.  Wherever you have a method or property, you should rewrite it by getting rid of the preceding “this.” and replacing the equals sign in your method definition with a colon.  Finally, a comma must be inserted after each method or property definition except the last.  For example, this:



this.initialize = function() {
    Custom.UI.FloatingBehavior.callBaseMethod(this, ‘initialize’);

}


becomes this:


 



initialize: function() {
     Custom.UI.FloatingBehavior.callBaseMethod(this, ‘initialize’);

},


 


17. Type descriptors are gone.  This means you no longer need the getDescriptor method or the Sys.TypeDescriptor.addType call to register your Type Descriptor.  There is an alternate grammar for writing type descriptors using JSON, but my code worked fine without it.  I think it is meant for writing extenders.


 


18. Hooking up event handlers to DOM events has been simplified.  You used to need to define a delegate for the DOM event, and then use the attachEvent and detachEvent methods to link the delegate with your handler function.  In the beta 2, all of this is encapsulated and you will only need two super functions, $addHandler and $removeHandler.  You should probably place your $addHandler method to your initialize method, and $removeHandler to your dispose method.  The syntax for $addHandler will typically look like this:


$addHandler(this.get_element(), ‘mousedown’, YourMouseDownHandlerFunction)

$removeHandler takes the same parameters.  One thing worth noting is that, whereas the reference to the DOM event used to use the IE specific event name, in this case ‘onmousedown’, the designers of ASP.Net Ajax have now opted to use the naming convention adopted by Firefox and Safari. 


 


19. The last touch: add the following lines as the last bit of code in your script file:



if(typeof(Sys) !== “undefined”)
Sys.Application.notifyScriptLoaded();


You basically just need to do this.  It may even be one of the rare instances in programming where you don’t even need to know why you are doing it since, as far as I know, you will never encounter a situation where you won’t put it in your script.  My vague understanding of the reason, though, is that the ASP.Net Ajax page lifecycle needs to know when scripts are loaded; both IE and Firefox throw events when a page has completed loading.  Safari, however, does not.  notifyScriptLoaded() provides a common way to let all browsers know when scripts have been loaded and it is safe to work with the included classes and functions.


 


 


Bibliography (of sorts):


Here are the good guides I referred to at the top of this post: Bertrand LeRoy‘s post on javascript prototypes, Eilon Lipton‘s blog, the comments here: Scott Guthrie, Sean Burke‘s migration guide, Miljan Braticevic‘s experience with upgrading the Component Art tools.  The most comprehensive guide to using Ajax Extensions beta 2 is actually the upgrade guide provided by Microsoft Ajax Team here: AspNet AJAX CTP to Beta Whitepaper. I used the official online documentation, http://ajax.asp.net/docs/Default.aspx, mainly to figure out which namespaces to use and where the various functions I needed had been moved to.  Finally, using the search functionality on the ASP.Net Ajax forums helped me get over many minor difficulties.

One thought on “Converting to ASP.NET Ajax Beta 2 (A Guide for the Perplexed)

  1. Easily, the accumulation is rattling the large on this laudable substance. I happen with your conclusions and will thirstily wait overfamiliar to your prox updates. Expression thanks testament not meet be adequate, for the fantasti c pellucidity in your writing. I leave directly seize your rss provide to fulfill secluded of any updates. Worthy touch and some success in your mercantilism enterprize!

Comments are closed.