Click here to Skip to main content
Click here to Skip to main content
Articles » Web Development » Ajax » General » Downloads
 
Add your own
alternative version
Go to top

Magic AJAX: Applying AJAX to your existing Web Pages

, 28 May 2007
How to apply AJAX technologies to your web pages without replacing ASP.NET controls and/or writing JavaScript code.
magicajax-030-net11.zip
magicajax
Examples
ExampleSite (.NET 2.0 only)
Web.sitemap
webparts
images
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
examples
App_Data
App_Code
Docs
Core
script
bin
MagicAjax.dll
magicajax-030-net20.zip
MagicAjax.dll
Web.sitemap
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
magicajax-030-source.zip
Web.sitemap
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
MagicAjax.snk
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
UI
Design
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Controls
ClientEventControls
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Extra
Entries.Old
Entries
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Interfaces
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Configuration
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
magicajax.zip
AJAXTest
AJAXTest.csproj.webinfo
Global.asax
Ajax
Ajax.csproj.user
Controls
Design
script
using System;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Ajax.Controls;

namespace Ajax
{
	/// <summary>
	/// It handles a CallBack request from the client and sends the appropriate javascript.
	/// </summary>
	/// <remarks>
	/// AjaxHttpModule handles the AcquireRequestState event of the HttpApplication, when
	/// the request has been authorized and the session state has been restored.
	/// 
	/// To use AjaxHttpModule for your application you must put
	/// 
	///		<httpModules>
	///			<add name="AjaxHttpModule" type="Ajax.AjaxHttpModule, Ajax" /> 
	///		</httpModules>
	///	
	/// in the system.web section of the web.config file.
	/// </remarks>
	public class AjaxHttpModule: IHttpModule
	{
		#region Static Properties
		private static bool completedCallBack;
		internal static bool CompletedCallBack
		{
			get { return completedCallBack; }
			set { completedCallBack = value; }
		}
		#endregion

		private PageFilter filter;

		#region Public Methods
		/// <summary>
		/// Member of the IHttpModule interface
		/// </summary>
		/// <param name="context"></param>
		public void Init(HttpApplication context)
		{
            context.AcquireRequestState += new EventHandler(Application_AcquireRequestState);
			context.EndRequest += new EventHandler(Application_EndRequest);
		}

		/// <summary>
		/// Member of the IHttpModule interface
		/// </summary>
		public void Dispose()
		{
		}
		#endregion

		#region Protected Methods
		/// <summary>
		/// Handles the AcquireRequestState event of the HttpApplication
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void Application_AcquireRequestState(object sender, EventArgs e)
		{
			if ( !CallBackHelper.IsCallBack )
				return;

			completedCallBack = false;

			HttpApplication application = (HttpApplication) sender;
			HttpContext context = application.Context;

			Page page = CallBackHelper.SessionPage;
			if (page == null)
			{
				// Session stored Page wasn't found, session must have been expired.
				// Have the browser do a refresh.
				// It will stop the current execution and will throw Application_EndRequest event
				CallBackHelper.Redirect (context.Request.RawUrl);
			}

			filter = new PageFilter(context.Response.Filter);
			context.Response.Filter = filter;

			ProcessCallBack(page);
			CallBackHelper.End();
		}

		/// <summary>
		/// Handles the EndRequest event of the Application
		/// </summary>
		/// <remarks>
		/// During a callback it checks if the request was ended because of a
		/// Response.Redirect or a Server.Transfer and sends the appropriate javascript
		/// for each case.
		/// </remarks>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected virtual void Application_EndRequest(object sender, EventArgs e)
		{
			if ( !CallBackHelper.IsCallBack || completedCallBack )
				return;

			// There was a Response.Redirect or Server.Transfer during callback

			HttpApplication application = (HttpApplication) sender;
			HttpResponse response = application.Context.Response;

			int hhh = response.StatusCode;
			string uu = response.Status;

			if (response.RedirectLocation != null)
			{
				// Handle Response.Redirect
				CallBackHelper.Redirect (response.RedirectLocation);
			}
			else
			{
				// Handler Server.Transfer
				response.Clear();
				string html = filter.GetHtmlPage();
				CallBackHelper.WriteSetHtmlOfPageScript (html);
				CallBackHelper.WriteEndSignature();
			}
		}

		/// <summary>
		/// Raises the callback events on the Page and the child controls,
		/// and invokes the IRenderedByScript controls.
		/// </summary>
		/// <param name="page"></param>
		protected virtual void ProcessCallBack(Page page)
		{
			ReadOnlyArrayList postDataChangedControls;
			postDataChangedControls = new ReadOnlyArrayList(LoadPostDataOnChildren(page));

			if (page is IPostDataLoadedEventHandler)
				((IPostDataLoadedEventHandler)page).RaisePostDataLoadedEvent (postDataChangedControls);
			RaisePostDataLoadedOnChildren (page, postDataChangedControls);

			foreach (IPostBackDataHandler handler in postDataChangedControls)
				handler.RaisePostDataChangedEvent();

			if (page is ICallBackEventHandler)
				((ICallBackEventHandler)page).RaiseCallBackEvent();
			RaiseCallBackOnChildren (page);

			if ( CallBackHelper.CallBackType == CallBackType.Control )
			{
				string target = HttpContext.Current.Request.Form["__AJAX_EVENTTARGET"];
				string argument = HttpContext.Current.Request.Form["__AJAX_EVENTARGUMENT"];
				RaisePostBackEventInChild (page, target, argument);
			}

			if (page is IPreRenderByScriptEventHandler)
				((IPreRenderByScriptEventHandler)page).RaisePreRenderByScriptEvent();
			RaisePreRenderByScriptOnChildren (page);

			if (page is IRenderedByScript)
				((IRenderedByScript)page).RenderByScript();
			InvokeRenderedByScriptControls (page);
		}

		/// <summary>
		/// Raises PostDataLoaded event on the children of the supplied control.
		/// </summary>
		/// <remarks>
		/// This is a recursive method. It goes through the control collection tree
		/// and raises the PostDataLoaded event on all the controls that implement the
		/// IPostDataLoadedEventHandler interface.
		/// </remarks>
		/// <param name="control"></param>
		protected virtual void RaisePostDataLoadedOnChildren (Control control, ReadOnlyArrayList changedControls)
		{
			for (int i=0; i < control.Controls.Count; i++)
			{
				Control con = control.Controls[i];
				if (con is IPostDataLoadedEventHandler)
				{
					IPostDataLoadedEventHandler ajaxcon = (IPostDataLoadedEventHandler) con;
					ajaxcon.RaisePostDataLoadedEvent (changedControls);
				}

				RaisePostDataLoadedOnChildren (con, changedControls);
			}
		}

		/// <summary>
		/// Raises callback event on the children of the supplied control.
		/// </summary>
		/// <remarks>
		/// This is a recursive method. It goes through the control collection tree
		/// and raises the callback event on all the controls that implement the
		/// ICallBackEventHandler interface.
		/// </remarks>
		/// <param name="control"></param>
		protected virtual void RaiseCallBackOnChildren (Control control)
		{
			for (int i=0; i < control.Controls.Count; i++)
			{
				Control con = control.Controls[i];
				if (con is ICallBackEventHandler)
				{
					ICallBackEventHandler ajaxcon = (ICallBackEventHandler) con;
					ajaxcon.RaiseCallBackEvent();
				}

				RaiseCallBackOnChildren (con);
			}
		}

		/// <summary>
		/// Raises the PreRenderByScript event on the children of the supplied control.
		/// </summary>
		/// <remarks>
		/// This is a recursive method. It goes through the control collection tree
		/// and raises the PreRenderByScript event on all the controls of the
		/// RenderedByScriptControl class.
		/// </remarks>
		/// <param name="control"></param>
		protected virtual void RaisePreRenderByScriptOnChildren (Control control)
		{
			for (int i=0; i < control.Controls.Count; i++)
			{
				Control con = control.Controls[i];

				if (con.Visible)
				{
					if (con is IPreRenderByScriptEventHandler)
					{
						IPreRenderByScriptEventHandler ajaxcon = (IPreRenderByScriptEventHandler) con;
						ajaxcon.RaisePreRenderByScriptEvent();
					}

					RaisePreRenderByScriptOnChildren (con);
				}
			}
		}

		/// <summary>
		/// It invokes the RenderByScript method on the children of the supplied control.
		/// </summary>
		/// <remarks>
		/// This is a recursive method. It goes through the control collection tree
		/// and invokes the RenderByScript method on all the controls of the
		/// RenderedByScriptControl class.
		/// </remarks>
		/// <param name="control"></param>
		protected virtual void InvokeRenderedByScriptControls (Control control)
		{
			for (int i=0; i < control.Controls.Count; i++)
			{
				Control con = control.Controls[i];

				if (con.Visible)
				{
					if (con is IRenderedByScript)
					{
						IRenderedByScript ajaxcon = (IRenderedByScript) con;
						ajaxcon.RenderByScript();
					}

					InvokeRenderedByScriptControls (con);
				}
			}
		}

		/// <summary>
		/// Loads post data on controls during a CallBack.
		/// </summary>
		protected virtual ArrayList LoadPostDataOnChildren (Control control)
		{
			ArrayList list = new ArrayList();
			HttpRequest request = HttpContext.Current.Request;

			for (int i=0; i < control.Controls.Count; i++)
			{
				Control con = control.Controls[i];

				if (con.Visible)
				{
					if (con is IPostBackDataHandler)
					{
						IPostBackDataHandler handler = (IPostBackDataHandler) con;

						if (con is RadioButtonList)
						{
							// For some strange reason, if the RadioButtonList selection
							// changes, the SelectedIndexChanged event is invoked every time
							// a callback occurs. So, do a manual check.
                            RadioButtonList rbList = (RadioButtonList) con;
							string postData = request.Form[rbList.UniqueID];
							if (postData != null && postData != rbList.SelectedValue)
							{
								if (handler.LoadPostData(con.UniqueID, request.Form))
									list.Add (con);
							}
						}
						else if (con is CheckBoxList)
						{
							CheckBoxList cbList = (CheckBoxList) con;
							bool changed = false;
							for (int listItem=0; listItem < cbList.Items.Count; listItem++)
							{
								bool oldSelected = cbList.Items[listItem].Selected;
								handler.LoadPostData(String.Format("{0}:{1}", con.UniqueID, listItem), request.Form);
								if (oldSelected != cbList.Items[listItem].Selected)
									changed = true;
							}

							if (changed)
								list.Add (con);
						}
						else
						{
							if (handler.LoadPostData(con.UniqueID, request.Form))
							{
								list.Add (con);
							}
						}
					}

					list.AddRange (LoadPostDataOnChildren(con));
				}
			}

			return list;
		}

		/// <summary>
		/// Raises a PostBack event of a control during a CallBack.
		/// </summary>
		/// <param name="eventTarget"></param>
		/// <param name="eventArgument"></param>
		protected virtual void RaisePostBackEventInChild(Page page, string eventTarget, string eventArgument)
		{
			Control eventcontrol = page.FindControl(eventTarget);

			if (eventcontrol is IPostBackEventHandler)
				((IPostBackEventHandler)eventcontrol).RaisePostBackEvent(eventArgument);
		}
		#endregion

		/// <summary>
		/// Used to store and retrieve the html rendering of the page during a callback
		/// </summary>
		private class PageFilter : Stream
		{
			private Stream responseStream;
			private Stream memStream;

			public PageFilter (Stream responseStream)
			{
				this.responseStream = responseStream;
				this.memStream = new MemoryStream();
			}

			public string GetHtmlPage()
			{
				byte[] buffer = new byte[memStream.Length];

				memStream.Position = 0;
				memStream.Read (buffer, 0, (int)memStream.Length);

				return HttpContext.Current.Response.ContentEncoding.GetString(buffer);
			}

			#region Stream overrides
			public override bool CanRead
			{
				get { return true;}
			}

			public override bool CanSeek
			{
				get { return true; }
			}

			public override bool CanWrite
			{
				get { return true; }
			}

			public override void Close()
			{
				responseStream.Close ();
			}

			public override void Flush()
			{
				responseStream.Flush ();
			}

			public override long Length
			{
				get { return responseStream.Length; }
			}

			public override long Position
			{
				get { return responseStream.Position; }
				set { responseStream.Position = value; }
			}

			public override long Seek(long offset, SeekOrigin origin)
			{
				return responseStream.Seek (offset, origin);
			}

			public override void SetLength(long length)
			{
				responseStream.SetLength (length);
			}

			public override int Read(byte[] buffer, int offset, int count)
			{
				return responseStream.Read (buffer, offset, count);
			}

			public override void Write(byte[] buffer, int offset, int count)
			{
				responseStream.Write (buffer, offset, count);

				if ( CallBackHelper.IsCallBack )
					memStream.Write (buffer, offset, count);
			}
			#endregion
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Argiris Kirtzidis
Web Developer
Greece Greece
No Biography provided

| Advertise | Privacy | Mobile
Web02 | 2.8.140921.1 | Last Updated 28 May 2007
Article Copyright 2005 by Argiris Kirtzidis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid