Click here to Skip to main content
15,895,667 members
Articles / Web Development / ASP.NET
Article

Remote Scripting

Rate me:
Please Sign up or sign in to vote.
4.85/5 (86 votes)
25 Apr 20058 min read 753.2K   6.5K   196   255
Use client-side JavaScript to remotely invoke methods in ASP.NET pages.

Contents

Introduction

How many times have you been on a web page and you selected a value in a drop down box, only to suddenly see the whole page refresh so that it can fetch values for another drop down box? I see it all the time in car web sites. You select the Make of the car and the whole page is reloaded to bring back all the corresponding Models. Then you select the Model and the whole page is reloaded again to bring back all the corresponding Trims. Annoying, isn't it?

Some sites avoid this problem by preloading all the possible alternatives in memory. This works, but there are times when the amount of data is just too overwhelming for all the possible combinations.

Remote Scripting offers a better alternative. Instead of the whole page refreshing, a hidden request is made to the server to execute a method which returns back just the data that needs to be changed on the page. The result is a smoother user experience. Indeed, Remote Scripting brings some of the benefits of a traditional fat-client application to a web application. It can be used to refresh individual controls, to validate controls, or even to process a form without having to post the whole page to the server. It's cool stuff and it works on all major browsers!

Over the years, I've seen two popular remote scripting implementations. Back in the days of Visual InterDev 6.0, Microsoft provided client and server-side include files inside its _ScriptLibrary directory. I used it in a few projects and it worked quite well. The only problem I found was that it used a Java applet to handle the communications, so it tended to be sluggish at times. Then I started doing JSP and I found a better alternative called JSRS. Depending on the browser, it created a hidden element on the page that submitted the request to the server which then responded back to it. It was more efficient, but it only allowed the remote calls to be asynchronous.

Now with ASP.NET, I've once again needed to use Remote Scripting. I initially wrote a small class library in C# that provided support for both Microsoft's and JSRS's clients. But then I decided to see if I could come up with a better client implementation, and I believe I did. I came up with a hybrid solution based on both of the existing implementations, which I believe looks and works better. This article presents my Remote Scripting client and server side implementation for ASP.NET. Enjoy!

Demo

The downloadables include a file called rsDemo.aspx which has a fully working example of this code. It also demonstrates how to populate the drop downs using data from an XML file (rsDemo.xml). The link below goes to the demo page. When you change the Type, the Amount is repopulated using Remote Scripting.

Usage

I've strived to make my Remote Scripting implementation as simple and easy to use as possible. There are just a few simple steps to take on the client and server side to get it working. Be sure to look at the rsDemo.aspx file to get the complete picture.

Client-side

  1. Include rs.js in your .aspx page, like this:
    HTML
    <script language="'JavaScript'" src='/scripts/rs.js'></script>
  2. Use RS.Execute to invoke the remote method using JavaScript, like this:
    JavaScript
    function dropdown_onchange()
    {
      RS.Execute("page.aspx", "RemoteMethod", 
                 "optionalParam1", "optionalParam2", ...., 
                 callback, optionalErrorCallback,
                 optionalCallbackParam2, optionalCallbackParam3, 
                 optionalCallbackParam4);
    }

    The page.aspx file is where the RemoteMethod will be executed. The RemoteMethod's parameters are optional, so don't pass anything if they're not needed. The callback function (which is not a string parameter) is also optional and if passed will be called when the server's response is received. Its first parameter will be the value returned by the RemoteMethod, converted to a string. If there's a chance for error, you can also pass a second callback method that will receive the error description. If it's not passed, an alert box will be shown in case of error. If you pass optionalCallbackParam2, optionalCallbackParam3, or optionalCallbackParam4, they will also be passed to the callbacks. Keep in mind that RS.Execute is asynchronous, so the callbacks are the only way to know when and what was returned from the server.

  3. If you care about the RemoteMethod's result, add a callback method to get it, and optionally do the same for error messages:
    JavaScript
    function callback(result)
    {
      alert("The remote method returned this: " + result);
    }
    
    function errorCallback(result)
    {
      alert("An error occurred while invoking the remote method: " + result);
    }

Server-side

  1. Make sure AMS.Web.RemoteScripting.dll file is deployed to your site's bin directory.
  2. At the top of the Page_Load method, add these two lines:
    C#
    if (AMS.Web.RemoteScripting.InvokeMethod(Page))
      return;

    This accomplishes several things. First, it checks if the client is making a remote request on the page. If not, this method returns false (and Page_Load proceeds). If there is a client request, the remote method is invoked, its return value is written to the response, and it is then sent back to the client immediately.

    If your page does not have a Page_Load method (and you don't want to add one), you can just place those two lines at the top of your page inside <% %> tags.

  3. Add the remote method as a public instance or static member of your Page class:
    C#
    public string RemoteMethod(string param1, string param2, ... )
    {
      return "This is what the client sent me: \n" + param1 
             + "\n" + param2 + ... ;
    }

    If you just need to read a field's value, you can use a property instead of a method:

    C#
    public string RemoteProperty
    { 
      get { return m_someField; };
    }

    The return type does not need to be a string but it will be converted to a string before going back to the client. The parameters must all be of type string, and the method (or property) must be public or you'll receive a System.MissingMethodException error.

    As an alternative to remotely executing a public method or property of the Page, you may also directly execute a public method or property of a control on the page. For example, if you want to retrieve the Text property of a TextBox control called "txtAmount", you can pass "txtAmount.Text" as the name of the remote method in RS.Execute.

Notes

I added a method called ReplaceOptions inside rs.js. It makes it convenient to repopulate a drop down box with the results of a remote method. It expects the result string to be formatted like this:

XML
"<option value='0'>Text 0</option><option selected value='1'>Text 1</option>..."

You can use it like this inside the callback:

JavaScript
function callback(result)
{
  RS.ReplaceOptions(document.form.theDropDown, result);
}

An even better alternative is RS.ReplaceOptions2, which may be passed directly to RS.Execute as the callback function:

JavaScript
function dropdown_onchange()
{
  RS.Execute("page.aspx", "RemoteMethod", 
             "optionalParam1", "optionalParam2", ...., 
             RS.ReplaceOptions2, document.form.theDropDown);
}

RS.ReplaceOptions2 takes the same parameters as RS.ReplaceOptions but in the opposite order so that it can be used as a callback. This allows you to do everything in one call!

The RS object also has a member called debug that you can set to true (RS.debug = true;) to show the hidden elements used for communicating with the server.

On the server side, you'll see that the RemoteScripting class is designed to handle any of three possible clients: Mine (RS), JSRS, and Microsoft's (MSRS). The type of client is determined based on the parameters passed into the request. If you have your own client implementation, my architecture makes it easy to add an implementation for it by deriving from the RemoteScriptingClient class.

Microsoft is the only remote client implementation that supports synchronous calls to the server, so if you absolutely need that, you can use it. All you need on the client is the rs.htm and RSProxy.class files from the _ScriptLibrary directory. I personally don't recommend it since it ties up the browser until the response is sent back and it requires the browser to support Java. Nevertheless, I added support for it inside the RemoteScriptingClient class.

Something else to point out: for drop downs that are populated and repopulated based on remote scripting calls, I recommend you remove them from the ViewState (EnableViewState=false), since you'll need to populate them on every trip back to the server. In other words, regardless of whether IsPostBack is true or not, you'll need to populate these drop downs, so it will be a waste to save them to the ViewState.

History

  • Version 1.0 - Mar 12, 2004.
    • Initial release.
  • Version 2.0 - Sept 3, 2004.
    • Enhanced RS.Execute to allow passing of up to three additional parameters to the callbacks (aside from the result of the remote method).
    • Enhanced RemoteScriptingClient.InvokeMethod to allow execution of a method or property of a control of the page. Thanks to Jonathan Marbutt for the idea and his implementation.
    • Fixed bug that didn't allow remote scripting to work with the Opera browser. Thanks to Christoph Weber for reporting it.
    • Fixed bug that prevented remote scripting from working in SSL sites. Thanks to Peter for reporting it and providing the solution.
    • Fixed bug that was filling the call pool when remote methods were executed over 100 times. Thanks to emadns and Anonymous for reporting it.
    • Fixed bug that was taking the result string and replacing any slashes (/) with \/.
  • Version 2.1 - Feb 7, 2005.
    • Fixed small problem in RemoteScriptingCall.setResult of rs.js when simultaneous calls were made to RS.Execute. Thanks to Eddy A for reporting it and providing the solution.
    • Fixed bug with RS.ReplaceOptions of rs.js which wasn't properly handling values containing angle brackets. Thanks to pussicatt0102 for reporting it.
    • Updated the rsDemo.aspx page to demonstrate how to make it work with a Submit button.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I've done extensive work with C++, MFC, COM, and ATL on the Windows side. On the Web side, I've worked with VB, ASP, JavaScript, and COM+. I've also been involved with server-side Java, which includes JSP, Servlets, and EJB, and more recently with ASP.NET/C#.

Comments and Discussions

 
GeneralRe: error_callback function not being called Pin
Edward Callender14-May-04 11:40
Edward Callender14-May-04 11:40 
GeneralRe: error_callback function not being called Pin
Alvaro Mendez17-May-04 16:24
Alvaro Mendez17-May-04 16:24 
GeneralSome help with Remote Scripting please.... Pin
Lou23m13-May-04 6:39
Lou23m13-May-04 6:39 
GeneralRe: Some help with Remote Scripting please.... Pin
Lou23m13-May-04 12:16
Lou23m13-May-04 12:16 
GeneralRe: Some help with Remote Scripting please.... Pin
Alvaro Mendez13-May-04 18:08
Alvaro Mendez13-May-04 18:08 
GeneralRe: Some help with Remote Scripting please.... Pin
Lou23m14-May-04 3:50
Lou23m14-May-04 3:50 
GeneralRe: Some help with Remote Scripting please.... Pin
Alvaro Mendez17-May-04 16:26
Alvaro Mendez17-May-04 16:26 
GeneralCalling Methods from Sub Controls! Pin
jmarbutt17-Apr-04 5:06
jmarbutt17-Apr-04 5:06 
This was a great article and I only had to make one little addition to call functions on sub controls. I modified the RemoteScripting.cs to handle calling remote procedures on sub controls. So here it is, let me know what you think:
 /**<br />
 * Remote Scripting Class Library<br />
 * <br />
 * Written by Alvaro Mendez<br />
 * Copyright (c) 2004. All Rights Reserved.<br />
 * <br />
 * The AMS.Web namespace contains web-related interfaces and classes <br />
 * that don't fall into any particular category.<br />
 * This file contains the RemoteScripting classes.<br />
 * <br />
 * The code is thoroughly documented, however, if you have any questions, <br />
 * feel free to email me at alvaromendez@consultant.com.  Also, if you <br />
 * decide to this in a commercial application I would appreciate an email <br />
 * message letting me know.<br />
 *<br />
 * This code may be used in compiled form in any way you desire. This<br />
 * file may be redistributed unmodified by any means providing it is <br />
 * not sold for profit without the authors written consent, and <br />
 * providing that this notice and the authors name and all copyright <br />
 * notices remains intact. This file and the accompanying source code <br />
 * may not be hosted on a website or bulletin board without the author's <br />
 * written permission.<br />
 * <br />
 * This file is provided "as is" with no expressed or implied warranty.<br />
 * The author accepts no liability for any damage/loss of business that<br />
 * this product may cause.<br />
 *<br />
 * Last Updated: Mar. 12, 2004<br />
 */<br />
<br />
using System;<br />
using System.Web;<br />
using System.Text;<br />
using System.IO;<br />
using System.Web.UI;<br />
using System.Reflection;<br />
using System.Diagnostics;<br />
<br />
namespace AMS.Web<br />
{<br />
	/// <summary><br />
	///   Class that handles Remote Scripting.  Based on the remote web client, this class<br />
	///   can be used to invoke a method on the Page. </summary><br />
	public class RemoteScripting<br />
	{	    <br />
		private RemoteScriptingClient m_client;		<br />
		<br />
		/// <summary><br />
		///   Constructs the object and determines the type of remote client, if any. </summary><br />
		/// <param name="page"><br />
		///   The object representing the web page where the client wants to invoke the method. </param><br />
		public RemoteScripting(Page page)<br />
		{<br />
			m_client = RemoteScriptingClient.Create(page);<br />
		}<br />
				<br />
		/// <summary><br />
		///   Gets the object for the client that made the remote request, if any. </summary><br />
		/// <remarks><br />
		///   If the client requested to invoke a method, this property returns an object<br />
		///   representing the client; otherwise it returns null. </remarks><br />
		public RemoteScriptingClient Client<br />
		{<br />
			get <br />
			{ <br />
				return m_client;<br />
			}<br />
		}<br />
		<br />
		/// <summary><br />
		///   Invokes the method on the page object as requested by the web client, if any. </summary><br />
		/// <param name="page"><br />
		///   The object representing the web page where the client wants to invoke the method. </param><br />
		/// <returns><br />
		///   If the client requested to invoke a method, the return value is true; otherwise it's false. </returns><br />
		/// <remarks><br />
		///   This method conveniently combines the creation of a RemoteScripting object and subsequently <br />
		///   calling its InvokeMethod instance method.  It first verifies that a remote call was made and <br />
		///   if so makes it, writes the result to the response, sends it back to the client, and then returns true. </remarks><br />
		public static bool InvokeMethod(Page page)<br />
		{<br />
			return InvokeMethod(page, true);<br />
		}<br />
<br />
		/// <summary><br />
		///   Invokes the method on the page object as requested by the web client, if any. </summary><br />
		/// <param name="page"><br />
		///   The object representing the web page where the client wants to invoke the method. </param><br />
		/// <param name="endResponse"><br />
		///   If true and the client requested to invoke a method, <br />
		///   Response.End will be called after the method is invoked. </param><br />
		/// <returns><br />
		///   If the client requested to invoke a method, the return value is true; otherwise it's false. </returns><br />
		/// <remarks><br />
		///   This method conveniently combines the creation of a RemoteScripting object and subsequently <br />
		///   calling its InvokeMethod instance method.  The endResponse parameter allows for the extra convenience of <br />
		///   causing the result to be sent back to the client immediately.  <br />
		///   This method first verifies that a remote call was made and if so makes it, writes the result to <br />
		///   the response, and then returns true. </remarks><br />
		public static bool InvokeMethod(Page page, bool endResponse)<br />
		{<br />
			RemoteScripting rs = new RemoteScripting(page);<br />
			return rs.InvokeMethod(endResponse);<br />
		}<br />
<br />
		/// <summary><br />
		///   Invokes the method on the page object as requested by the web client, if any. </summary><br />
		/// <returns><br />
		///   If the client requested to invoke a method, the return value is true; otherwise it's false. </returns><br />
		/// <remarks><br />
		///   This method first verifies that a remote call was made and <br />
		///   if so makes it, writes the result to the response, sends it back to the client, and then returns true. <br />
		///   The remote call is based on the Request parameters of the Page object passed to the constructor, which <br />
		///   is also used to write back the result via its Response property. </remarks><br />
		public bool InvokeMethod()<br />
		{<br />
			return InvokeMethod(true);<br />
		}<br />
<br />
		/// <summary><br />
		///   Invokes the method on the page object as requested by the web client, if any. </summary><br />
		/// <param name="endResponse"><br />
		///   If true and the client requested to invoke a method, <br />
		///   Response.End will be called after the method is invoked. </param><br />
		/// <returns><br />
		///   If the client requested to invoke a method, the return value is true; otherwise it's false. </returns><br />
		/// <remarks><br />
		///   This method first verifies that a remote call was made and if so makes it, writes the result to <br />
		///   the response, and then returns true.  The remote call is based on<br />
		///   the Request parameters of the Page object passed to the constructor, which <br />
		///   is also used to write back the result via its Response property. The endResponse <br />
		///   parameter allows for the extra convenience of causing the result to be sent back <br />
		///   to the client immediately.  </remarks><br />
		public bool InvokeMethod(bool endResponse)<br />
		{	<br />
			if (m_client == null)<br />
				return false;<br />
			<br />
			m_client.InvokeMethod(endResponse);	<br />
			return true;<br />
		}<br />
	}<br />
<br />
	////////////////////////////////////////////////////////////////////////////////////////////////<br />
	<br />
	/// <summary><br />
	///   Class that represents a Remote Scripting client. </summary><br />
	public abstract class RemoteScriptingClient<br />
	{<br />
		/// <summary> The object representing the web page where the client wants to invoke the method. </summary><br />
		protected Page m_page;<br />
		<br />
		/// <summary><br />
		///   Constructs the object and stores the page object internally. </summary><br />
		/// <param name="page"><br />
		///   The object representing the web page where the client wants to invoke the method. </param><br />
		protected RemoteScriptingClient(Page page)<br />
		{		<br />
			m_page = page;<br />
		}<br />
		<br />
		/// <summary><br />
		///   Creates a client object based on the parameters passed to the page. </summary><br />
		/// <param name="page"><br />
		///   The object representing the web page requested by the client. </param><br />
		/// <returns><br />
		///   If the client requested to invoke a method, the return value is an object representing it; <br />
		///   otherwise it's null. </returns><br />
		/// <remarks><br />
		///   This method determines if a client is making a remote call and if so what type <br />
		///   of client is is (RS, JS, or MS).  This is needed to properly interpret the<br />
		///   request and then to respond to it.  </remarks><br />
		public static RemoteScriptingClient Create(Page page)<br />
		{<br />
			if (page.Request.Params["RC"] != null)<br />
				return new RS(page);<br />
			if (page.Request.Params["RS"] != null || page.Request.Params["C"] != null)<br />
				return new JS(page);<br />
			if (page.Request.Params["_method"] != null)<br />
				return new MS(page);				<br />
			return null;<br />
		}	<br />
		<br />
		/// <summary><br />
		///   Gets the object representing the web page requested by the client. </summary><br />
		/// <remarks><br />
		///   This object should contain an instance or static method with same name as <br />
		///   one to be invoked by the client. </remarks><br />
		public Page Page<br />
		{<br />
			get <br />
			{ <br />
				return m_page; <br />
			}<br />
		}		<br />
<br />
		/// <summary><br />
		///   Gets the name of the method to be invoked. </summary><br />
		/// <remarks><br />
		///   This is retrieved from the parameters passed to the page, which are specific to each client. </remarks><br />
		public abstract string Method { get; }<br />
<br />
		/// <summary><br />
		///   Gets a string array with the arguments (parameters) to be passed <br />
		///   to the method to be invoked. </summary><br />
		/// <remarks><br />
		///   This is retrieved from the parameters passed to the page, which are specific to each client. </remarks><br />
		public abstract string[] Arguments { get; }<br />
<br />
		/// <summary><br />
		///   Retrieves the method's return value inside a string formatted based on the client's requirements. </summary><br />
		/// <param name="returnValue"><br />
		///   The value returned by the invoked method. </param><br />
		/// <param name="success"><br />
		///   Indicator of whether the method succeeded or not. </param><br />
		/// <returns><br />
		///   The return value is a string formatted based on the client's requirements containing<br />
		///   the result of the invoked method. </returns><br />
		public abstract string GetResult(string returnValue, bool success);<br />
		<br />
		/// <summary><br />
		///   Invokes the method on the page object as requested by client. </summary><br />
		/// <param name="endResponse"><br />
		///   If true Response.End will be called after the method is invoked. </param><br />
		/// <remarks><br />
		///   After the method is invoked, its result is written to the response.<br />
		///   The endResponse parameter allows for the extra convenience of causing <br />
		///   the result to be sent back to the client immediately.  </remarks><br />
		public void InvokeMethod(bool endResponse)<br />
		{		<br />
			InvokeMethod();<br />
<br />
			if (endResponse)<br />
				m_page.Response.End();											<br />
		}<br />
<br />
		/// <summary><br />
		///   Invokes the method on the page object as requested by client. </summary><br />
		/// <remarks><br />
		///   After the method is invoked, its result is written to the response. </remarks><br />
		private System.Web.UI.Control FindChildControl(System.Web.UI.Control ParentControl , string UniqueID ) <br />
		{<br />
			System.Web.UI.Control ReturnControl;<br />
			<br />
			foreach (System.Web.UI.Control c in ParentControl.Controls)<br />
			{<br />
				if (c.UniqueID.Replace(":", "_") == UniqueID )<br />
				{<br />
					ReturnControl = c;<br />
					return ReturnControl;<br />
				}<br />
				else<br />
				{<br />
					ReturnControl = FindChildControl(c, UniqueID);<br />
					if ( ReturnControl !=  null ) <br />
					{<br />
						return ReturnControl;<br />
					}<br />
				}<br />
			}<br />
			return null;<br />
			<br />
		}	<br />
	<br />
		<br />
		public virtual void InvokeMethod()<br />
		{		<br />
			bool success = true;<br />
			string returnValue = "";<br />
<br />
			try<br />
			{<br />
				if (Method != null)<br />
				{<br />
					//Check to see if it is being called from a sub control<br />
					if (Method.IndexOf(".") >= 0 )<br />
					{<br />
						//System.Web.UI.Control cControl = GetControl(Method);<br />
						System.Web.UI.Control cControl = FindChildControl(m_page,Method.Substring(0,Method.IndexOf(".")));<br />
						object result = cControl.GetType().InvokeMember(Method.Substring(Method.LastIndexOf(".") + 1), BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.GetProperty, null, cControl, Arguments);<br />
						if (result != null)<br />
							returnValue = result.ToString();<br />
							<br />
					}<br />
					else<br />
					{<br />
						object result = m_page.GetType().InvokeMember(Method, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.GetProperty, null, m_page, Arguments);<br />
						if (result != null)<br />
							returnValue = result.ToString();<br />
					}<br />
				}<br />
			}<br />
			catch (TargetInvocationException ex)<br />
			{<br />
				success = false;<br />
				returnValue = ex.InnerException.Message;  // send back the real message<br />
			}<br />
			catch (Exception ex)<br />
			{<br />
				m_page.Trace.Write("RemoteScriptingClient.Invoke", "Error invoking remote scripting method '" + Method + "'", ex);<br />
<br />
				success = false;<br />
				returnValue = ex.ToString();  // it's probably a bug - send back everything<br />
			}<br />
<br />
			try  // Write the output string<br />
			{<br />
				m_page.Response.Clear();<br />
				m_page.Response.Write(GetResult(returnValue, success));<br />
			}<br />
			catch (Exception ex)<br />
			{<br />
				m_page.Trace.Write("RemoteScriptingClient.Invoke", "Error writing the remote scripting result.", ex);<br />
			}			<br />
		}<br />
<br />
		/// <summary><br />
		///   Encodes a string like a URL but without the + for spaces. </summary><br />
		/// <param name="str"><br />
		///   The string to return encoded. </param><br />
		/// <returns><br />
		///   The encoded string. </returns><br />
		protected string Encode(string str)<br />
		{<br />
			return HttpUtility.UrlEncode(str).Replace("+", "%20");<br />
		}			<br />
		<br />
		////////////////////////////////////////////////////////////////////////////////////////////////<br />
		<br />
		/// <summary><br />
		///   Class that represents a JSRS Remote Scripting client. </summary><br />
		/// <remarks><br />
		///   JSRS is a popular remote client implementation found at http://www.ashleyit.com/rs/jsrs/test.htm.<br />
		///   It's simple and it supports multiple browsers. </remarks><br />
		public class JS : RemoteScriptingClient<br />
		{<br />
			/// <summary><br />
			///   Constructs the object and stores the page object internally. </summary><br />
			/// <param name="page"><br />
			///   The object representing the web page where the client wants to invoke the method. </param><br />
			internal JS(Page page) :<br />
				base(page)<br />
			{<br />
			}<br />
<br />
			/// <summary><br />
			///   Gets the name of the method to be invoked. </summary><br />
			/// <remarks><br />
			///   This is retrieved from the 'F' parameter, passed to the page. </remarks><br />
			public override string Method <br />
			{ <br />
				get<br />
				{<br />
					return m_page.Request.Params["F"];<br />
				}<br />
			}<br />
			<br />
			/// <summary><br />
			///   Gets a string array with the arguments (parameters) to be passed <br />
			///   to the method to be invoked. </summary><br />
			/// <remarks><br />
			///   This is retrieved from the 'P' parameters, passed to the page. </remarks><br />
			public override string[] Arguments<br />
			{ <br />
				get<br />
				{<br />
					// Count the parameters				<br />
					int paramCount = 0;<br />
					while (m_page.Request.Params["P" + paramCount] != null)<br />
						paramCount++;				<br />
				<br />
					string[] args = new string[paramCount];<br />
					for (int i = 0; i < paramCount; i++)<br />
					{<br />
						args[i] = m_page.Request.Params["P" + i];<br />
						args[i] = args[i].Substring(1, args[i].Length - 2);							<br />
					}	<br />
<br />
					return args;<br />
				}			<br />
			}										<br />
<br />
			/// <summary><br />
			///   Retrieves the method's return value inside a string formatted based for the JSRS client. </summary><br />
			/// <param name="returnValue"><br />
			///   The value returned by the invoked method. </param><br />
			/// <param name="success"><br />
			///   Indicator of whether the method succeeded or not. </param><br />
			/// <returns><br />
			///   The return value is a string formatted for JSRS containing<br />
			///   the result of the invoked method. </returns><br />
			public override string GetResult(string returnValue, bool success)<br />
			{<br />
				StringBuilder sb = new StringBuilder("<html><head></head><body onload=\"p=document.layers?parentLayer:window.parent;");<br />
<br />
				string context = m_page.Request.Params["C"];<br />
				if (context == null)<br />
					context = m_page.Request.Params["RS"];<br />
<br />
				if (success)<br />
					sb.Append("p.jsrsLoaded('" + context + "');\">jsrsPayload:<br><form name=\"jsrs_Form\"><textarea rows=\"4\" cols=\"80\" name=\"jsrs_Payload\">" + returnValue.Replace("/", "\\/") + "</textarea></form>");<br />
				else<br />
					sb.Append("p.jsrsError('" + context + "','jsrsError: " + Encode(returnValue).Replace("'", "\\'") + "');\">jsrsError: " + returnValue);				<br />
<br />
				sb.Append("</body></html>");<br />
				return sb.ToString();			<br />
			}<br />
		}<br />
		<br />
		////////////////////////////////////////////////////////////////////////////////////////////////<br />
		 <br />
		/// <summary><br />
		///   Class that represents my Remote Scripting client. </summary><br />
		/// <remarks><br />
		///   RS is my own remote client implementation which is basically a rewrite of JSRS.<br />
		///   It's simpler and cleaner than JSRS and it also supports multiple browsers. </remarks><br />
		public class RS : JS<br />
		{<br />
			internal RS(Page page) :<br />
				base(page)<br />
			{<br />
			}<br />
			<br />
			/// <summary><br />
			///   Gets the name of the method to be invoked. </summary><br />
			/// <remarks><br />
			///   This is retrieved from the 'M' parameter, passed to the page. </remarks><br />
			public override string Method <br />
			{ <br />
				get<br />
				{<br />
					return m_page.Request.Params["M"];<br />
				}<br />
			}<br />
<br />
			/// <summary><br />
			///   Retrieves the method's return value inside a string formatted based for the RS client. </summary><br />
			/// <param name="returnValue"><br />
			///   The value returned by the invoked method. </param><br />
			/// <param name="success"><br />
			///   Indicator of whether the method succeeded or not. </param><br />
			/// <returns><br />
			///   The return value is a string formatted for RS containing<br />
			///   the result of the invoked method. </returns><br />
			public override string GetResult(string returnValue, bool success)<br />
			{<br />
				string callID = m_page.Request.Params["RC"];<br />
				string result = success ? "true" : "false";<br />
				<br />
				return<br />
					"<html><body onload=\"p=document.layers?parentLayer:window.parent;p.RS.pool['" + callID + "'].setResult(" + result + ");\">" + <br />
					"Payload:<br><form name=\"rsForm\"><textarea rows=\"4\" cols=\"80\" name=\"rsPayload\">" + returnValue.Replace("/", "\\/") + "</textarea></form>" +<br />
					"</body></html>";					<br />
			}<br />
<br />
		}		<br />
		<br />
		////////////////////////////////////////////////////////////////////////////////////////////////<br />
<br />
		/// <summary><br />
		///   Class that represents Microsoft's Remote Scripting client. </summary><br />
		/// <remarks><br />
		///   Microsoft's remote client implementation is found in the _ScriptLibrary directory installed<br />
		///   by Visual InterDev 6.0 on new web sites.  It is very well written and it supports synchronous <br />
		///   calls since it uses a Java applet to communicate with the server.  Its drawback is that the <br />
		///   Java applet performs slower and it may require the user to download of the Java run-time. </remarks><br />
		public class MS : RemoteScriptingClient<br />
		{<br />
			internal MS(Page page) :<br />
				base(page)<br />
			{<br />
			}<br />
<br />
			/// <summary><br />
			///   Gets the name of the method to be invoked. </summary><br />
			/// <remarks><br />
			///   This is retrieved from the '_method' parameter, passed to the page. </remarks><br />
			public override string Method <br />
			{ <br />
				get<br />
				{<br />
					return m_page.Request.Params["_method"];<br />
				}<br />
			}<br />
<br />
			/// <summary><br />
			///   Gets a string array with the arguments (parameters) to be passed <br />
			///   to the method to be invoked. </summary><br />
			/// <remarks><br />
			///   This is retrieved from the 'p' parameters, passed to the page. </remarks><br />
			public override string[] Arguments<br />
			{ <br />
				get<br />
				{<br />
					int paramCount = Convert.ToInt32(m_page.Request.Params["pcount"]);<br />
					string[] args = new string[paramCount];<br />
<br />
					for (int i = 0; i < paramCount; i++)<br />
						args[i] = m_page.Request.Params["p" + i];<br />
						<br />
					return args;<br />
				}										<br />
			}<br />
<br />
			/// <summary><br />
			///   Retrieves the method's return value inside a string formatted based for the MSRS client. </summary><br />
			/// <param name="returnValue"><br />
			///   The value returned by the invoked method. </param><br />
			/// <param name="success"><br />
			///   Indicator of whether the method succeeded or not. </param><br />
			/// <returns><br />
			///   The return value is a string formatted for MSRS containing<br />
			///   the result of the invoked method. </returns><br />
			/// <remarks><br />
			///   Microsoft's Remote Scripting has three return types: SIMPLE, EVAL_OBJECT, and ERROR.<br />
			///   We only support SIMPLE and ERROR. </remarks><br />
			public override string GetResult(string returnValue, bool success)<br />
			{<br />
				return "<METHOD VERSION=\"1.0.8044\"><RETURN_VALUE TYPE=" + (success ? "SIMPLE" : "ERROR") + ">" + Encode(returnValue) + "</RETURN_VALUE></METHOD>";<br />
			}<br />
		}		<br />
	}<br />
}<br />


Jonathan Marbutt
MCSD,MCAD,MCDBA
GeneralRe: Calling Methods from Sub Controls! Pin
Alvaro Mendez25-Jun-04 5:36
Alvaro Mendez25-Jun-04 5:36 
GeneralWeb Service Behavior Pin
JasonBSteele27-Mar-04 4:31
JasonBSteele27-Mar-04 4:31 
GeneralRe: Web Service Behavior Pin
Alvaro Mendez29-Mar-04 11:22
Alvaro Mendez29-Mar-04 11:22 
GeneralRe: Web Service Behavior Pin
JasonBSteele29-Mar-04 20:54
JasonBSteele29-Mar-04 20:54 
QuestionVB.NET version? Pin
schonne26-Mar-04 19:30
schonne26-Mar-04 19:30 
AnswerRe: VB.NET version? Pin
Alvaro Mendez26-Mar-04 22:41
Alvaro Mendez26-Mar-04 22:41 
GeneralFor Dropdowns might be better to.. Pin
Rocky Moore25-Mar-04 23:15
Rocky Moore25-Mar-04 23:15 
QuestionEver consider XMLHttp? Pin
mleo25-Mar-04 6:24
mleo25-Mar-04 6:24 
AnswerRe: Ever consider XMLHttp? Pin
Joseph Dunne25-Mar-04 12:04
sussJoseph Dunne25-Mar-04 12:04 
GeneralRe: Ever consider XMLHttp? Pin
Alvaro Mendez26-Mar-04 3:37
Alvaro Mendez26-Mar-04 3:37 
AnswerRe: Ever consider XMLHttp? Pin
Alvaro Mendez25-Mar-04 12:36
Alvaro Mendez25-Mar-04 12:36 
Generalproblem downloading Pin
leaffere25-Mar-04 1:16
leaffere25-Mar-04 1:16 
GeneralNo problem here Pin
Alvaro Mendez25-Mar-04 12:22
Alvaro Mendez25-Mar-04 12:22 
GeneralDoes not work with Opera browser Pin
Christoph Weber23-Mar-04 23:32
Christoph Weber23-Mar-04 23:32 
GeneralIt does now Pin
Alvaro Mendez24-Mar-04 6:42
Alvaro Mendez24-Mar-04 6:42 
GeneralRe: It does now Pin
Christoph Weber24-Mar-04 11:03
Christoph Weber24-Mar-04 11:03 
GeneralRe: It does now Pin
Alvaro Mendez24-Mar-04 12:27
Alvaro Mendez24-Mar-04 12:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.