Using the AJAX Library in ASP.NET websites
Creating Client Scripts
Client scripts add dynamic nature to web UI.
AJAX has pushed resurgence of JavaScript on client.
Three approaches to defining client script:
- Define script block on webpage - might define client-side code or include reference to JavaScript files.
- Use ClientScriptManager to dynamically add JavaScript to page based on server-side processing
- Use ScriptManager control to register JavaScript with webpage.
Adding script blocks to ASP.NET webpage
Traditional way to work with JavaScript on webpage.
Does not take advantage of features built into AJAX Library.
Script element not created dynamically.
Useful when want basic JavaScript functionality on page, e.g. hiding area of webpage when button clicked.
Script should be placed within head section of ASPX markup. If using cild page based on a master page add this to the HeadContent tag, e.g.:
<asp:Content ID="HeaderContent" runat="server">
<script language="javascript" type="text/javascript">
...
</script>
</asp:Content>
If JavaScript can be used across multiple pages should externalised into separate .js file to allow for reuse and caching.
<script type="text/javascript" src="SiteScript.js" />
For ASP.NET controls onClick used to connect Button to its server-side event, should use onClientClick to execute client side javascript.
Can reference ASP.NET controls within client-side JavaScript. Use the controls ClientId property to reference it. This property value generated based on ClientIDMode attribute:
- AutoID - concatenate each ID of parent containers with ID of control, each segment separated by _ character
- Static - set to controls ID
- Predictable - concatenate each ClientID of parent containers with ID of control, each segment separated by _ character
- Inherit - inherits ClientIDMode from container
Dynamically adding script to ASP.NET page
May need to do if controls generated at runtime, or infor added to age determines JavaScript that should be used.
Use ClientScriptManager to register JavaScript dynamically.
Instance of ClientScriptManager exposed through Pages ClientScript property.
To add script define within string or point to file and call Page.ClientScript.RegisterClientScriptBlocks providing type (typically instance of page or control), key (uniquely identify script), script itself and bool indicating if registration should generate script tags.
Can register client scripts to execute only on page submission. Page could use this code to validate submission and cancel if necessary. Do this via the Page.ClientScript.RegisterOnSubmiStatement
Registering via the ScriptManager Control
ScriptManager automatically registers ASP.NET AJAX extensions.
Can register own scripts with a page, either declaratively or programmatically.
To declaratively add place reference to script file with ScriptManager element:
<scriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="AppScript.js" />
</Scripts>
</scriptManager>
To register via code create instance of ScriptReference class and add to the Scripts collection of the ScriptManager control.
If not using AJAX features better off using ClientScriptManager object as does not have overhead of ScriptManager server control.
Only scripts registered with ScriptManager are available for use in partial-page update scenarios.
Creating Client Callbacks
Controls such as the UpdatePanel make it easy to create a client callback (call to server followed by call back to client from server). May be times when need more control. To do so follow these steps:
-
Implement System.Web.UI.CallBackEventHandler for the ASP.NET page. This server-side interface is used to set up the receive call from client (RaiseCallbackEvent) and method that returns results to client (GetCallbackResults) public partial class Default : System.Web.UI.Page, System.Web.UI.ICallbackEventHandler
-
Implement RaiseCallbackEvent method for IcallbackEventHandler interface. Called by client. Use to receive parameter values.
string _callBackArgs;
public void RaiseCallbackEvent(string eventArgument)
{
_callBackArgs = eventArgument;
}
- Implement GetCallbackResult method for IcallbackEventHandler interface. Results sent as string back to client
public string GetCallbackResult()
{
return _callBackArgs;
}
The client-side code:
-
Add client script called by server as a result of server processing. Used to process results coming back from server. Functions name should be same as that registered with GetCallbackEventReference inside server-side code when page is loaded. Protected void Page_Load(object sender, EventArgs e) { string callbackRef = Page.ClientScript.GetCallbackEventReference(his, "args", "ClientCallbackFunction", "");
-
Create JavaScript function that calls server from client - typically created in server-side code when page is loaded. Doing so allows registration of client-side function via RegisterClientScriptBlock of the ClientScriptManager control. This function used by page controls to initiate client-side call to server. string callbackScript = String.Format("function MySeverCall(args) {{{0};}}, callbackRef); Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "MyServerCall", callbackScript, true); }
-
ASP.NET will generate JavaScript function that performs the calling between client and server. Function generated when GetCallbackEventReference method of ClientScriptManager is called in server-side code.
Then write page markup which includes client script that receives callback from server (in this example ClientCallbackFunction). Also mist initiate call to server from client (in this example MyServerCall)
<script type="text/javascript">
function ClientCallbackFunction(args) { LabelMessage.innerText = args; }
</script>
<asp:DropDownList ID="DropDownListChoice" runat="server" OnChange="MyServerCall(DropDownListChoice.Value)">
<asp:ListItem>Choice 1</asp:ListITem>
<asp:ListItem>Choice 2</asp:ListITem>
</asp:DropDownList>
<asp:Label ID="LabelMessage" runat="server" />
Working with Microsoft AJAX Library
Acts as wrapper to JavaScript, provides:
- OO support - allows definition of namespaces, classes, event handlers, interfaces, inheritance, data types, enumerations and reflection.
- Base classes - Global namespace extends JavaScript to include String, Number, Date, Boolean, Array, Object. Adds Type class to register new namespaces, classes, etc.
- Framework (set of namespaces) - root namespace of Sys (client side equivalent of System), others include Sys.Net, Sys.Services, Sys.UI, Sys.WebForms, Sys.Serialization
- Browser compatibility - takes browser quirks into account
- Debug support - extension to make debugging easier. Two version of library - debug and release. Tracing support via Sys.Debug.trace
- Globalization support - Single JacvaScript code base provides localised UI support without posting back to server. Number and date format methods work with language and culture settings of browser.
Not available unless SciptManager control present on page, or MicrosoftAjax.js included in page (latter allows code to be used outside of ASP.NET).
AJAX Library Namespaces
- Global - extension of JavaScript itself, e.g Number, String, Date, etc. given new functionality. Type class used to register OO items (namespaces, classes, interfaces, etc.) in JavaScript
- Sys - root of AJAX library. Contains framework for AJAX programming with JavaScript. Application class connects to client-side events. Component class registers and creates components created within library.
- Sys.Net - focuses con communications between client and server. Basis for partial page updates, calling web services, etc.
- Sys.Serialization - used to serialize / de-serialize classes for transfer between client and serve
- Sys.Services - classes to work with authentication and profile services
- Sys.UI - used to AJAX features to UI, e.g. Behavior, Control and DomElement classes.
- Sys.WebForms - classes for partial-page updates as used by UpdatePanel control. PageRequestManager class used to customise async postbacks.
Object-Oriented AJAX Development
JavaScript missing key OO features such as namespaces, interfaces, inheritance, fields, properties, enumerations, events, reflection, etc. Microsoft AJAX library provides these features.
In many cases do not need these features in client-side code.
If building own controls or creating very specific client-side behaviour these features will be useful.
To use library:
- define requirements
- create JavaScript class in .js file that provides methods, properties, etc. needed to meet requirements
- register .js file with page
Namespaces
Encapsulates code in library for easier classification and reference.
Helps manage name collisions.
When registered with library, namespaces are available via IntelliSense.
Use registerNamespace method on Type class to define namespace:
Type.registerNamespace("Contoso.Utilities");
Classes
Naming convention is Namespace.ClassName
Assign class name to a function that servers as class constructor, e.g.
Contoso.Utilities.ChangePasswordValidator = function(requirePasswordNotMatch, requireNumber)
{
Contoso.Utilities.ChangePasswordValidator.Initialize(this);
this.RequirePasswordNotMatch = requirePasswordNotMatch;
this.RequireNumber = requireNumber;
this._passwordRuleViolations = new Array();
}
Note, class is set to a function that also acts as the constructor.
The call to initializeBase ensures base classes from which this class derive are initialised.
Derive from Sys.Components, Sys.UI.Behavior, Sys.UI.Control if want class to be part of AJAX control.
Define fields, properties, methods, etc. by defining a prototype.
To do this set the JavaScript prototype equal to class definition.
To define fields simply declare variables at class level:
Contoso.Utilities.ChangePasswordValidator.prototype =
{
RequirePasswordNotMatch : Boolean;
RequireNumber : Boolean;
}
Javascript does not support properties directly.
Instead define methods (get and set) that act as properties.
Naming convention is set_propertyName and get_propertyName.
Internal variables defined with leading _ which indicates to library that they should remain private.
set_currentPassword: function(value)
{
this._currentPassword = value;
}
get_passwordRuleViolations: function()
{
return this._passwordRuleViolations;
}
Add methods to class prototype in same way as functions...
CheckPasswordStrngth: function(password)
{
var strPass = new String(password.ToString());
if (strPass.length <= 4)
return Contoso.Utilities.PasswordStrength.Weak;
else
return Contoso.Utilities.PasswordStrength.Strong;
}
Must register class with AJAX library for it to be available to ScriptManager. Do this by calling the registerClass extension on your object, which takes three arguments; typeName, baseType and interfaceType, e.g.:
Contoso.Utilities.ChangePasswordValidator.registerClass('Contoso.Utilities.ChangePasswordValidator'. Null, Sys.IDisposable);
Enumerations
Define in same way as class., e.g.:
Contoso.Utilities.PasswordStrength = function(){};
Contoso.Utilities.PasswordStrength.prototype =
{
Weak : 1,
Strong : 2;
}
Contoso.Utilities.PasswordStrength.registerEnum("Contoso.Utilities.PasswordStrength");
Inheritance
Implemented through registerClass method by setting baseType property during registration.
To override function simply redefine using same name in new class.
Interfaces
Indicate class should implement interface via registerClass method. Third parameter is an array that represents the interfaceTypes the class implements.
To create interface define in same way as class, but with method stubs:
Contoso.Utilities.IValidationLogic = function(){};
Contoso.Utilities.IValidationLogic.prototype =
{
set_currentPassword: function(){},
get_passwordRuleViolations: function(){};
}
Contoso.Utilities.IValidationLogic.registerInterface("Contoso.Utilities.IValidationLogic ");
Using Custom Classes
First register class with ScriptManager.
<asp:ScriptManager ID="ScriptManager!" runat="server">
<Scripts>
<asp:ScriptReference path="ContosoUtilities.js" />
</Scripts>
</asp:ScriptManager>
Can then use as required in page level script.
AJAX Client-side Life Cycle Events
AJAX library includes client-based event life cycle - use this to intercept event as page runs
Life cycle of client similar to that of server, include events for init, load, unload and disposing.
Register an event by using add_{event}
syntax, e.g.:
Sys.Application.add_load(PageLoad);
...
function PageLoad(sender)
{
...
}
Can unregister using remove_{event}
syntax, e.g.:
Sys.Application.remove_load(PageLoad);
Another important event related class is Sys.WebForms.PageRequestManager used for partial-page updates and asynchronous postbacks. Includes following events:
- initializeRequest - before async postback starts
- beginRequest - async postback event sent to server
- pageLoading - async postback response received
- pageLoaded - content loaded from results of async postback
- endRequest - async postback completed
Building Client Capabilities with AJAX
Three types of client object can be created:
- Sys.Component - do not generate UI elements. Work as common controls providing functionality across pages, e.g. timer.
- Sys.UI.Control - typically relate to single DOM element (e.g. input box, button). Provide additional functionality to DOM element.
- Sys.UI.Behavior - represent behaviours that can be added to one or more DOM elements at design time. An example is a behaviour that opens a new window when cursor points to an element, can then apply this behaviour to button, input box, hyper link, etc.
Creating AJAX client component
Create when want class that is managed by AJAX Library but does not directly work with UI.
When defining class constructor, be sure to initialise the base:
Type.registerNamespace("AjaxEnabled");
AjaxEnabled.PasswordStrengthComponent = function() {
AjaxEnabled.PasswordStrengthComponent.initialzeBase(this);
}
When overriding base methods should also call the base method:
initialize: function () {
AjaxEnabled.PasswordStrengthComponent.callBaseMethod(this, 'initialze');
}
When registering component, indicate inheriting from Sys.Component
AjaxEnabled.PasswordStrengthComponent.registerClass('AjaxEnabled.PasswordStrengthComponent', Sys.Component);
When working with JavaScript in code editor can get IntelliSense by adding reference to Microsoft AJAX Library. Do this by embedding reference in comment:
/// <reference name="MicrosoftAjax.js"/>
Creating AJAX client component
Provides additional functionality to DOM element.
Works as single, encapsulated control (like ASP.NET server controls).
Possible to attach to existing DOM element, but more robust to create custom server control that embeds the AJAX client control to provide additional behaviours.
Need to indicate which DOM element is to be extended. This is done via constructor which takes an element parameter, representing the DOM element to be extended:
Type.registerNamespace("AjaxEnabled");
AjaxEnabled.PassTextBox = function(element) {
AjaxEnabled.PassTextBox.initialzeBase(this, [element]);
...
}
Whilst defining class need to indicate within the initialize function which which DOM element events to extend. First initialise the base class. Then create a delegate method (_onKeyUp) and register this as a handler for the element (via the $addHandlers method). Second argument to $addHandlers is array of events to intercept (represented by the event name and the method to call when event raised).
initialize: function () {
AjaxEnabled.PassTextBox.callBaseMethod(this, 'initialze');
this._onKeyUpHandler = Function.createDelegate(this, this._onKeyUp);
$addHandlers(this.getElement(), { 'keyup': this._onKeyUpHandler }, this);
}
Create method to handle event taking single event argument. Within event handling code have access to DOM element that this control is extending (via this.get_element()):
_onKeyUp: function (e) {
var stringth = this.returnPasswordStrength(this.get_element().value);
...
}
Register class with AJAX Library, indicating inherits from Sys.UI.Control:
AjaxEnabled.PassTextBox.registerClass('AjaxEnabled.PassTextBox', Sys.UI.Control);
Using AJAX Client Control
First add ScriptManager control to page, within it reference script containing client control.
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="PasswordStength.js" />
</Scripts>
</asp:ScriptManager>
Add DOM element to extend to page. For example the above code extends text boxes so can be used with <input>
or <asp:TextBox>
.
<asp:TextBox ID="TextBoxPass" runat="server" TextMode="Password" />
Finally create instance of client control and connect to DOM element. Typically performed inside application init method of AJAX library.
Inside init override use $create method (shortcut to SysComponent.create) to create instance of control and connect it to DOM element. Has five parameters:
- type - indicates class intend to create
- properties - provide properties (and their values) for the class being created
- events - events to register from client code to control
- references - references to other components
- element - indicates DOM element to attach control to
var app = Sys.Application;
app.add_init(appInit);
function appInit(sender, args) {
$create(AjaxEnabled.PassTxtBox, {weakCssClass : 'weak', strongCssClass: 'strong'}, null, null, $get('TextBoxPass'));
}
Encapsulating AJAX Client Control Into Custom Server Control
More robust solution for creating AJAX enabled controls.
Define server-side control and use it to write the custom control.
Can be part of web site in App_Code directory, or embedded in own assembly.
The control must implement IScriptControl interface - which is used to embed JavaScript into control.
public class PassTextBoxCs : TextBox, IScriptControl
{
...
Need to gain access to ScriptManager control
private ScriptManager sMgr;
protected override void OnPreRender(EventArgs e) {
if (!this.DesignMode) {
sMgr = ScriptManager.GetCurrent(Page);
sMgr.RegisterScript(this);
...
Define properties and then provide GetScriptDescriptors method to map these to properties of the control.
public string WeakCssClass;
public string StrongCssClass;
protected virtual IEnumerable<ScriptDescriptor> GetScrptDescriptors() {
ScriptControlDescriptor des = new ScriptControlDescriptor("AjaxEnabled.PassTextBox", this.ClientID);
des.AddProperty("weakCssClass", this.WeakCssClass);
des.AddProperty("strongCssClass", this.StrongCssClass);
return new ScriptDescriptor [] { des };
}
Register JavaScript code used by control via GetSciptReferences method. Two ways to implement, one for controls in App_Code directory and another for controls within assemblies. To reference a file:
protected virtual IEnumerable<ScriptReference> GetScrptReferences() {
ScriptReference ref = new ScriptReference();
ref.Path = ResolveClientUrl("PasswordStrength.js");
return new ScriptReference[]{ ref };
}
To reference an assembly do not set the Path property, instead set the Assembly property to the name of the DLL and the Name property to the name of the resource in the DLL that holds the script.
Then register custom control with page together with a ScriptManager:
<%@ Register Namespace="AjaxEnabled" TagPrefix="AjaxEnabled" %>
<asp:ScriptManager ID="ScriptManager1" runat="server"/>
<AjaxEnabled:PassTextBox ID="textbox1" runat="server" TextMode="Password" WeakCssClass="weak" StringCssClass="strong" />
Creating AJAX Behaviour for Client Controls
Works in similar way to AJAX client control,
Biggest difference - behaviours are general and extend one or more controls.
Inherit from Sys.UI.Behavior instead of Sys.UI.Control
Encapsulating AJAX Behaviour as Extender Control
Rather than being custom control based on single web control, a custom behaviour control inherits from ExtenderControl class.
When define class add TargetControlType attribute to class definition:
[TargetControlType(typeof(Control))]
public class MyExtender : ExtenderControl
{
}
Using AJAX Behaviour
Use like any other custom control.
First register on page, define instance of control in markup. As it is an Extender control must also define control it extends via the TargetControlId property.
<asp:Button ID="Button1" runat="server" />
<ajaxEnabled: MyExtender runat="server" ID="MyExtender1" TargetControlId="Button1" />