cdo

导航

Ajax.NET - A free library for the Microsoft .NET Framework

Ajax.NET - A free library for the Microsoft .NET Framework

Asynchronous JavaScript with XmlHttpRequest - C# Example

Contact Address / Impressum

This web site is a demonstration page of the Ajax.NET library I have build in my free time.

Michael Schwarz
Meisenweg 2
90547 Stein
Germany

Use my contact form at http://weblogs.asp.net/mschwarz/contact.aspx to give feedback, ideas and if you got any error.

Ajax.NET - Download Details

Download the latest Ajax.dll (5.7.22.2) to use it for free in your web projects.

You can also download the Ajax.dll (5.7.25.1) Beta for the new Microsoft .NET Framework 2.0.

The source code of Ajax.NET is now available! More details...

NEW: Ajax.NET Professional

Did you had a look at the beta version of Ajax.NET Professional? More security features like AJAX Token, encryption on client-side JavaScript and on the server, faster JavaScript wrapper files cached using HTTP ETag header values, using Namespaces on the client-side JavaScript to ensure that there are no variable name conflicts, a fully new written JSON parser that will allow you to use any object as method argument or result value without writing an IAjaxObjectConverter, ...

Download the Ajax.NET Professional Library and start working on the client-side JavaScript as you are already working on the server.

Some of the new features will be added in the next few weeks to the Ajax.NET Library available at BorgWorx.

The Most Intelligent Add-In To VisualStudio.NET Your Laptop as a second monitor
ReSharper laptop as a monitor

To learn more about AJAX and Ajax.NET:
Implementing AJAX in ASP.NET (Karl Seguin)
Ajax.NET - Key Benefits and Ideas PowerPoint Presentation
Intro to Ajax and the Ajax.NET Library
AJAX on Wikipedia DE FR KO ZH
A New Approach to Web Applications
Who is visiting this web site? Last 20 Visitors

Visit my blog at http://weblogs.asp.net/mschwarz/.

The library can be downloaded from this web page. As this project is a technology demonstration of XmlHttp requests there is no warranty:

THE LIBRARY IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE LIBRARY IS FREE OF DEFECTS, MERCHANTABLE,
FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
OF THE LIBRARY IS WITH YOU. SHOULD ANY PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL
DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION.

To download this C# example click here.
Switch to the VB.NET example.

There is a usage guide (will be updated in the next days) available for the first version of the free Ajax.NET:
AjaxGuide.doc
quickGuide.txt



Neues zu ASP.NET 2.0
Die finale Version von Visual Studio 2005 und SQL Server 2005 kommt im November 2005.
Bei der 12. ASP konferenz spielt die neue Version von ASP.NET 2.0 die zentrale Rolle. Neue Controls, 70 % weniger Code und eine Menge mehr, das müssen Sie sich einfach ansehen.

Highlights
  • AJAX.NET Erfinder und Guru Michael Schwarz zeigt erstmalig wie Microsoft aus AJAX Atlas macht.
  • Die magische Zahl 7: IIS 7 und IE 7
  • Die drei Musketiere, Karsten, Hannes und Christoph MVP's für ASP.NET

Weitere Infos unter www.asp-konferenz.de.


Examples using the free Ajax.NET library

Send feedback form with Unicode chars

This example will post a form to the server, invoke the Test1 method there and return a HTML string.

On the server you will have a typical method with an additional attribute:

[Ajax.AjaxMethod]
public string Test1(string firstName, string familyName, string email, string comment)
{
  string html = "";
	
  html += "Hello " + firstName + " " + familyName + "<br>";
  html += "Thank you for your comment <b>";
  html += System.Web.HttpUtility.HtmlEncode(comment);
  html += "</b>.";
	
  return html;
}
FirstName:
FamilyName:
Email:
My Comment:
Submit
Hello Michael æøå
Thank you for your comment (26.10.2005 07:01:04):
修正2.

If your browser does not accept displaying Unicode characters (like Japanese characters) you will see small boxes instead of the real char.


Send a custom type as argument

The second sample will show you how to pass a real .NET object as an argument for your method. The Test2 method will have a System.DateTime argument. The IAjaxObjectConverter will give you a simple to use client script to create the wrapper for .NET. On the client script you can use following script to create such an object:

var d = new DateTime(2005, 4, 20, 0, 0, 0);	// April 20th 2005

To call the AJAX.NET method you will write:

DemoMethods.Test2(d, callback);

The AJAX.NET wrapper on the server will check which converter can decode the Javascript object and passes the method a correct object. You can create your own IAjaxObjectConverters to allow every object to be returned or accepted.

[Ajax.AjaxMethod]
public string Test2(DateTime d)
{
  d = d.AddDays(1);
  return "The next day will be " + d.ToLongDateString() + ".";
}
DateTime (YYYY.MM.DD):
Submit
The next day will be Montag, 26. September 2005.

Currently I have following IAjaxObjectConverters:
- System.Collections.ArrayList
- System.Data.DataSet/DataTable/DataRow
- System.DateTime/TimeSpan
- System.Array


Use a System.Data.DataSet to fill a drop down box

Because you can return any object it is possible to fill a drop down box with only two lines. The list of countries will be fetched from the server after you have clicked on the link.

function callback(res)
{
  var html = [];
	
  for(var i=0; i<res.value.Tables[0].Rows.length; i++)
    html[html.length] = "<option>" + res.value.Tables[0].Rows[0].Country + "</option>";
		
  document.getElementById("display").innerHTML = "<select id=\"sel\">" + html.join("") + "</select>";
}
Country: Click here to load contry list...


Exception handling with Ajax.NET

The next example will throw a security exception on the server (System.Security.SecurityException). The callback handler will check if the error property is filled an will show the exception.

function callback(res)
{
  if(res.error != null)
    alert(res.error);
}

Click here to throw an exception on the server.

The error object will have three properties: name will be the type of the exception, description the .Message property of the exception thrown on the server, and number will be a unique ID (not yet implemented!). There is a toString() method that will output the name and the description as one string.


Session State handling with Ajax.NET

A lot of developers asked for the session station access. Now, we you can access your session variables.

First click on write to save the value i.e. "demo" to the session on the server. Now, you can press F5 (reload) and click on read. You should see the same value as you have written to the session state.

Session Handling Demo
Write value Write
Read value Read

On the server the C# method looks like following code:

[Ajax.AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
public void Test5(string value)
{
  System.Web.HttpContext.Current.Session["example"] = value;
}

[Ajax.AjaxMethod(HttpSessionStateRequirement.Read)]
public string Test6()
{
  if(System.Web.HttpContext.Current.Session["example"] != null)
    return (string)System.Web.HttpContext.Current.Session["test"];

  return "First set the value...";
}

Is it possible to wait for events?

Yes, you can use System.Threading.Thread to wait for events instead of pooling every second. Because the server process does not get informed when a client browser has been closed you should not use a infinite loop.

Why to use a loop at the server instead of polling every second? You will save client requests to the server that will use the Internet bandwidth and will create a new request on the server. So, you will have 10 requests if you will poll and one request if you loop at the server for 10 seconds!

Click here to start the process at the server. There is no timer at the client's javascript. In 10 seconds the request will response and call the client callback function which will show a alert box. There will be no network traffic until the method returns. Click on the link two times and you will get two alert boxes!

Note: You can have simultaneous requests at the same time, there are no restrictions.

[Ajax.AjaxMethod]
public void Test7()
{
  int c = 0;

  do
  {
    System.Threading.Thread.Sleep(1000);
    c++;
  }
  while(c < 10);
}

Using a context on the client-side Javascript

If I want to update several elements (i.e. DIV) on the screen I had to use different callback functions in the last release. Now, you can add a context that is accessable in the callback function.

The following sample will update the element you clicked on. There is only one Javascript function that will handle the callback:

<script language="javascript">
function test8(ele)
{
  DemoMethods.Test8(test8_callback, ele);  // the server-side method has no arguments!
}

function test8(res)
{
  if(res.error == null && res.context != null)
    res.context.innerHTML = res.value;
}
</script>

<span onclick="test8(this);">Element1</span>
<span onclick="test8(this);">Element2</span>

DIV elements: Click here Click here Click here


Return arrays and System.Collections.ICollection objects

The free Ajax.NET library is supporting arrays and objects the using the ICollection interface.

[Ajax.AjaxMethod]
public System.Collections.Specialized.StringCollection Test9()
{
  System.Collections.Specialized.StringCollection s = new System.Collections.Specialized.StringCollection();

  s.Add("Michael");
  s.Add("Hans");

  return s;
}

[Ajax.AjaxMethod]
public object[] Test10()
{
  object[] o = new object[3];

  o[0] = "Michael";
  o[1] = DateTime.Now;
  o[2] = true;

  return o;
}

[Ajax.AjaxMethod]
public System.Collections.ArrayList Test11()
{
  System.Collections.ArrayList a = new System.Collections.ArrayList();

  a.Add("Michael");
  a.Add(DateTime.Now);
  a.Add(true);
  
  Person p1 = new Person();
  p1.FirstName = "Michael";
			
  Person p2 = new Person();
  p2.FirstName = "Tanja";

  a.Add(p1);
  a.Add(p2);

  return a;
}

On the client-side Javascript you will get an array with each item:

function test11_callback(res)
{
  if(res.value[2])                           // bolean
    alert(res.value[1].toLocaleString());    // date
    
  alert(res.value[3].FirstName + " + " + res.value[4].FirstName);
}

Click here to get the result of the method DemoMethods.Test11.


Enable tracing for Ajax.NET requests

If you want to enable tracing for your Ajax.NET requests enable the tracing in your web.config file:

<configuration>
  <system.web>
    <trace enabled="true" requestLimit="100" pageOutput="false" />
  </system.web>
</configuration>

To view the trace open a new browser window and open the trace.axd page. This is the default ASP.NET page that will display tracing information off all your requests.

Category  Message                                                    From First(s) From Last(s)
Ajax.NET  Begin ProcessRequest   
Ajax.NET  Invoking CSharpSample.DemoMethods.Test11                   0,000181      0,000181 
Ajax.NET  JSON string: ['Michael',new Date(2005,4,10,9,39,27),true]  0,000365      0,000184 
Ajax.NET  End ProcessRequest                                         0,000387      0,000022

Use your own common Javascript file

Some developers asked for a debug version of the common.ashx (Javascript) file. With one setting in the web.config you can use your own common Javascript file:

<configuration>
  <configSections>
    <sectionGroup name="ajaxNet">
      <section name="ajaxSettings" type="Ajax.AjaxSettingsSectionHandler, Ajax" />
      <section name="ajaxConverters" type="Ajax.AjaxConverterSectionHandler, Ajax" />
    </sectionGroup>
  </configSections>

  <ajaxNet>
    <ajaxSettings>
      <commonAjax enabled="true" path="ajax.js" language="javascript" />
    </ajaxSettings>
  </ajaxNet>

The example above will include the ajax.js instead of the common.ashx.


Add/remove your own IAjaxObjectConverters

The free Ajax.NET library has already some useful build-in object converters. Currently there are following IAjaxObjectConverters available:

  • Ajax.JSON.ArrayListConverter (obsolete, replaced by IEnumerableConverter)
  • Ajax.JSON.DataRow/DataTable/DataSetConverter
  • Ajax.JSON.DateTime/TimeSpanConverter
and the Ajax.JSON.DefaultConverter which will use the .ToString() method to get the value of the object.

All of them are enabled be default. To remove or add your own IAjaxObjectConverters you can modify your web.config file:

<configuration>
  <configSections>
    <sectionGroup name="ajaxNet">
      <section name="ajaxSettings" type="Ajax.AjaxSettingsSectionHandler, Ajax" />
      <section name="ajaxConverters" type="Ajax.AjaxConverterSectionHandler, Ajax" />
    </sectionGroup>
  </configSections>

  <ajaxNet>
    <ajaxConverters>
      <add type="Namespace.Class1, Assembly" />
      <remove type="Ajax.JSON.DataSetConverter, Ajax" >
    </ajaxConverters>
  </ajaxNet>
</configuration>

The example above will add a converter Namespace.Class, Assembly and remove the default converter that will handle the DataSet objects.

To implement your own IAjaxObjectConverters the source code of the IEnumerableConvert.cs will be available in this exmaple. Feel free to download the source code here.

Return your own classes

With Ajax.NET you can return your own classes you are already using in C#. You only have to add the [Serializable] attribute to the class:

[Serializable]
public class Person
{
  public string FirstName;
  public string FamilyName;
  public int Age = 0;

  public Person NewChild()
  {
    Person p = new Person();
    p.FamilyName = FamilyName;

    return p;
  }

  public Person[] Children = null;
}

On the client-side you can use it like you will do it on the server:

function test12_callback(res)
{
  var s = res.value.FirstName + " " + res.value.FamilyName + ":\r\n";
	
  for(var i=0; i<res.value.Children.length; i++)
    s += "\t" + res.value.Children[i].FirstName + "\r\n";
	
  alert(s);
}

Click here to run the method above.


Use a System.Data.DataSet to retreive a SQL query

A lot of web applications are using the MSDE or Microsoft SQL Server to store data. In some case you want to return a complete DataSet (or DataTable/DataRow) to the client. With the free Ajax.NET library you can directly return a DataSet to the client without any need to convert. There is no sourc code change, only add the Ajax.AjaxMethod to the method:

[Ajax.AjaxMethod]
public DataSet Test15()
{
  SqlConnection conn = new SqlConnection("server=(local);Integrated Security=true;Initial Catalog=master;");
  SqlCommand cmd = new SqlCommand("SELECT [name], [filename] FROM dbo.sysdatabases", conn);
  SqlDataAdapter da = new SqlDataAdapter(cmd);

  DataSet ds = new DataSet();

  try
  {
    conn.Open();

    try
    {
      da.Fill(ds);    // fill DataSet with data
    }
    catch(Exception)
    {
      return null;
    }
    finally
    {
      conn.Close();
      conn.Dispose();
    }
  }
  catch(Exception)
  {
    return null;
  }

  return ds;
}

On the client-side Javascript I made a object that will have similar properties as the object in .NET. A DataTable will have the .Tables array, and each table will have their .Rows. The columns will be properties instead of an array, see the example below:

<script language="Javascript">

function test15_callback(res)
{
  if(typeof(res) == 'object' && typeof(res.Tables) == 'object')
  {
    var html = [];
    
    for(var i=0; i<res.Tables[0].Rows.length; i++)
      html[html.length] = '<p>' + res.Tables[0].Rows[i].ColumnName + '</p>';
   }
}

</script>

Each column value will have its correct data type: an integer will be a number, a DateTime will be a correct date object can be used in Javascript:

alert(res.Tables[0].Rows[0].DateTimeColumn.toLocaleString());
		
var y = res.Tables[0].Rows[0].IntegerColumn +10;

if(res.Tables[0].Rows[0].BooleanColumn == false)
  alert(res.Tables[0].Rows[0].StringColumn + 'my sample');

New: Some developers asked me if it is possible to select a table by name. I added a method to the returned DataSet where you can get the first table given by the name:

function test15_callback(res)
{
	var dt = res.value.getTable('Overview');
	
	if(dt != null)
		alert(dt.Rows.length);
}

Build a simple to use NewsTicker

Some developers asked me how to build a news ticker with the Ajax.NET library. I build a small example how you can do this. On the server-side we will have a database (or xml file, whatever) that stores the T to be displayed, the URL and the Seconds each news ticker will be on the screen. I'm using a simple array of 10 NewsTicker objects that hold these information and select one with System.Random:

[Ajax.AjaxMethod]
public NewsTicker Test13()
{
  NewsTicker[] nt = new NewsTicker[10];

  // following code will be replaced by getting a random item
  // from a database or xml file
  
  nt[0] = new NewsTicker("Ajax.NET Library", "http://ajax.schwarz-interactive.de", 20);
  nt[1] = new NewsTicker("Google Search", "http://www.google.com", 20);
  [...]
  nt[9] = new NewsTicker("Free Download!!", "http://ajax.schwarz-interactive.de", 20);

  Random r = new Random(System.DateTime.Now.Second);
  int i = r.Next(0, nt.Length);

  return nt[i];
}

The NewsTicker will be a own class the has the Serializable attribute:

[Serializable]
public class NewsTicker
{
  public NewsTicker(string text, string url, int duration)
  {
    this.Text = text;
    this.URL = url;
    this.Duration = duration;
  }

  public string Text;
  public string URL;
  public int Duration = 60;
}

On the client-side I will use the window.setTimeout command to wait the time is specified in the .Duration property:

function test13()
{
  // call the Ajax.NET method on the server to get
  // a new news ticker object
  
  DemoMethods.Test13(test13_callback);
}

function test13_callback(res)
{
  if(typeof(res.value) == 'object')
  {
    // display the news ticker
    
    document.getElementById('newsticker').innerHTML = '<a href="' + res.value.URL + '">' + res.value.Text + '</a>';
    window.setTimeout(test13, res.value.Duration * 1000);
  }
}

Here you can have a look on the live news ticker using Ajax.NET: NEW Ajax.NET Library


Is it possible to return images?

Currently I have implemented a ImageConverter that will support System.Drawing.Bitmap objects. On the server-side method you can create a Bitmap with GDI+ methods. On the client-side you will get a Image object that you can append to HTML elements. The Image object will have the .src property where you can get the URL of the image:

[Ajax.AjaxMethod]
public System.Drawing.Bitmap Test16()
{
  Bitmap bmp = new Bitmap(200, 50);
  Graphics g = Graphics.FromImage(bmp);
		
  g.FillRectangle(new SolidBrush(Color.Yellow), 0, 0, 199, 49);
  g.DrawString(DateTime.Now.ToString(), new Font("Arial", 10), new SolidBrush(Color.Red), 10, 10);

  return bmp;
}

On the client you will get a Image object that you can add to an element or where you can read the .src property:

function test16_callback(res)
{
  if(typeof(res.value) == 'object')
    document.getElementById("imageholder").appendChild(res.value);
}

Click here to create a bitmap showing the current time:

I got some requests what new on this? We could refresh images in the past, too! Ok, the difference is that you can return more than one image, or you can return a class with a lot of properties and one image. Others asked me if they should use it for MouseOvers. No, I think onmouseover is used with static images instead of dynamic rendered images. You can use it i.e. to return an object with a diagram and some values in a DataSet.

The images will be created in the subfolder images in the ApplicationPath. You can configure in which subfolder you will create temporary files and how long they should be available (delete files after x minutes):

<configSections>
  <sectionGroup name="ajaxNet">
    <section name="ajaxSettings" type="Ajax.AjaxSettingsSectionHandler, Ajax" />
  </sectionGroup>
</configSections>

<ajaxNet>
  <ajaxSettings>
    <temporaryFiles path="~/images" deleteAfter="1" />
  </ajaxSettings>
</ajaxNet>

Use arrays for argument values

Ajax.NET was designed to retreive structered data. But with the IAjaxObjectConverters we can get and post every value/object. Yesterday I added the possibility to use arrays as argument values:

test17([1,394,32,109,99]);
alert(DemoMethods.Test18( ["aaaa","bbbb","ccc\"ccccc"] ).value);

On the server-side method we will have a real integer array:

[Ajax.AjaxMethod]
public int Test17(int[] i)
{
  int r = 0;

  foreach(int ii in i)
    r += ii;

  return r;
}

[Ajax.AjaxMethod]
public string Test18(string[] s)
{
  string r = "";
  foreach(string ss in s)
    r += "<p>" + ss + "</p>\r\n";

  return r;
}

I only have done integer and string arrays, other arrays coomin soon. Click here to invoke the method DemoMethods.Test18 with an array including 3 strings.


Use HtmlControls as argument and return value

Now, it is possible to send any HtmlControl to the server-side method, use C# to change properties on it and return the object to the client. A lot of developers are afrait of writing Javascript code. I have added a small function that will update any HtmlControl.

Let's have a look at the server-side method. We will have two HtmlSelect controls on the page (DropDown):

<select id="sel1" onchange="test19(this.value);">
  <option value="">- Please select car -</option>
  <option value="VW">VW (Volkswagen)</option>
  <option value="Citroen">Citroen</option>
  <option value="Mercedes">Mercedes-Benz</option>
</select>
<span id="dropDisplay">
  <select>
    <option value="">- Please select car first -</option>
  </select>#
</select>

The first drop down list will display some car companies. The second one will be filled after changing the car company in the first one. In the onchange event we will call following code. Note: the second element is embedded in a parent control. I did not find a good solution that works in all common browsers. This will be changed in future releases!

The C# method will get the second drop down element as first argument, the second argument will be the selected value from the first drop down:

[Ajax.AjaxMethod]
public System.Web.UI.HtmlControls.HtmlSelect Test19(string car)
{
  System.Web.UI.HtmlControls.HtmlSelect control = new System.Web.UI.HtmlControls.HtmlSelect();

  switch(car)
  {
    case "VW":
      control.Items.Add("Golf");
      control.Items.Add("Passat");
      control.Items.Add("Beetle");
      control.Items.Add("Phaeton");
      break;

    case "Mercedes":
      control.Items.Add("S Class");
      control.Items.Add("E Class");
      control.Items.Add("A Class");
      control.Items.Add("M Class");
      break;

    case "Citroen":
      control.Items.Add("C3 Pluriel");
      control.Items.Add("C5 Break");
      control.Items.Add("C8");
      control.Items.Add("Berlingo");
      break;
  }

  return control;
}

The special function HtmlControlUpdate will get the Ajax.NET method as a string, the element to be updated and the optional arguments used for the C# method. In our example we will update the same control that we also send to the server:

<script type="text/javascript">
function test19(car)
{
	HtmlControlUpdate('DemoMethods.Test19', 'dropDisplay', car);
}
</script>

Try it, now! If you change the car company you will get a new drop down list with the available models:

If you want to update a control you can use the client-side element, send it to the server, modify it there and send it back to the client:

<script type="text/javascript">

HtmlControlUpdate('DemoMethods.Test19', 'dropDisplay', car, new HtmlControl('dropDisplay'));

</script>

The element with the ID dropDisplay will be send to the server. On the server it will be converted to a real System.Web.UI.HtmlControl. You can use .NET to change properties, add child controls,... and then the control on the client will be refreshed.

The following C# code will have a dropdown list as argument that I will fill with values on the server:

[Ajax.AjaxMethod]
public System.Web.UI.HtmlControls.HtmlSelect Test21(System.Web.UI.HtmlControls.HtmlSelect dropdown)
{
  dropdown.Items.Add("New option added at " + DateTime.Now);
  return dropdown;
}

Click here to add an item to the dropdown list.

Cache the requests to save CPU time

If you have same requests that will result the same result it would be nice to cache those requests. The only thing you have to add are the duration the request should be cached (in seconds):

[Ajax.AjaxMethod(30)]
public System.DateTime Test20()
{
  return DateTime.Now;
}

In the above example this call wil be cached for 30 seconds. If you click here you will only get the current time every 30 seconds.

Add namespace mappings to hide Ajax.NET script proxy locations

With the new version you can add namespace mappings in the web.config to hide internal knowledge about your assemblies:

<ajaxNet>
  <ajaxSettings>
    <urlNamespaceMappings>
      <add namespace="Namespace.ClassName,AssemblyName" path="MyPath" />
    </urlNamespaceMappings>
  </ajaxSettings>
</ajaxNet>

This will create the virtual proxy files in the folder /ajax/MyPath for the namespace Namespace.ClassName,AssemblyName.


posted on 2005-10-26 13:04  Cdo  阅读(1228)  评论(1编辑  收藏  举报