AJAX .Net Wrapper usage guide

7 篇文章 0 订阅
 
AJAX .Net Wrapper usage guide
 
 
Asynchronous JavaScript and XML (AJAX) has recently become the craze thanks, in no small part, to Google’s usage of it in Google Suggest as well as Google Maps. In ASP.Net terms, AJAX allows server-side processing to occur without requiring postback, thus enabling clients (browsers) with rich server-side capabilities. In other words it provides a framework for asynchronously dispatching and processing requests and responses from the server. AJAX leverages a number of existing technologies, which aren't particularly new, however fondness for what these technologies have to offer (collectively, they are AJAX) has recently soared.
 
Enter Michael Schwarz's AJAX .Net wrapper which allows ASP.Net developers to quickly and easily deploy pages capable of easily capitalizing on AJAX. Users should be cautioned that the wrapper is early in development, and as such isn't fully matured. 
 
It should be pointed out that technologies such as AJAX are very likely going to lead to violations of layered architectures (N-Tier). My opinion is that AJAX increases the likelihood that the presentation logic layer (or worse, the business layer) will leak into the presentation layer. Strict architects, like me, might cringe at this notion. I feel that even if AJAX is used in a manor which slightly violates layer boundaries, the payoffs are well worth it. Of course, that's something you'll need to look at for your specific project and environment.
 
 
AJAX relies on a broker to dispatch and process requests to and from the server. For this task, the .Net wrapper relies on the client-side XmlHttpRequest object. The XmlHttpRequest object is well supported by most browsers, making it the solution of choice. Since the goal of the wrapper is to hide the implementation of XmlHttpRequest, we'll forgo any detailed discussion about it.
 
The wrapper itself works by marking .Net functions as AJAX methods. Once marked, AJAX creates corresponding JavaScript functions which can be called client-side (liky any JavaScript functions) and that serve as proxies, using XmlHttpRequest. These proxies map back to the server-side function.
 
Complicated? It isn't. Let's look at a simplified example. Given the .Net function:
 
'VB.Net
public function Add(firstNumber as integer , secondNumber as integer ) as integer
  return firstNumber + secondNumber
end sub
 
//C#
public int Add( int firstNumber, int secondNumber)
{
   return firstNumber + secondNumber;
}
 
The AJAX .Net wrapper will automatically create a JavaScript function called "Add" which takes two parameters. When this function is called using JavaScript (on the client), the request will be passed to the server and the return value back to the client. 
We'll first go through the steps of "installing" the .dll for use in your project. If you know how to add a reference to a .dll file, skip this section.
 
First, if you don’t already have it, download the latest version of AJAX. Unzip the downloaded file and place the ajax.dll within a ref folder of your project. In Visual Studio.Net, right click the "References" node in the Solution Explorer and select Add Reference. In the newly opened dialog, click Browse and navigate to the ref/ajax.dll file. Click Open followed by Ok. You are now ready to start programming with the AJAX .Net wrapper.
 
If you’re having difficulty setting up the reference, check out:
 
The first step necessary to make everything work is to set up the wrapper's HttpHandler in the web.config. Without going into detailed explanation of what and how HttpHandlers work, it's sufficient to know that that they are used to process ASP.Net requests. For example, all requests for *.aspx pages are handled by the System.Web.UI.PageHandlerFactory class. Similarly we'll make all requests to ajax /*.ashx handled by the Ajax.PageHandlerFactory:
 
<configuration>
 <system.web>
    <httpHandlers>
      <add verb =" POST,GET " path =" ajax /*.ashx "
          
type =" Ajax.PageHandlerFactory, Ajax " />
    </httpHandlers> 
    ...
 <system.web>
</configuration>
 
The above code basically tells ASP.Net that any requests made that match the specified path ( ajax /*.ashx) are to be handled by Ajax.PageHandlerFactory, instead of the default handler factory. You don’t need to create an ajaxsubdirectory, this is a mythical directory simply used so that other HttpHandlers can use the .ashx extension with their own made-up subdirectories.
 
We are now ready to start coding. Create a new page, or open an existing one and in the code behind file, add the following code in the Page_Load event:
 
'vb.net
Public Class Index
  Inherits System.Web.UI.Page
 
 Private Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase .Load
    Ajax.Utility.RegisterTypeForAjax( GetType (Index))
  '...
 end sub
 '...
End Class
 
//C#
public class Index : System.Web.UI.Page{
   private void Page_Load( object sender, EventArgs e){
      Ajax.Utility.RegisterTypeForAjax( typeof( Index ) );     
      //...                                       
   }
   //... 
}
 
The call to RegisterTypeForAjax emits the following JavaScript on the page (alternatively, you could manually place the following two lines on the page):
 
<script language =" javascript " src =" ajax/common.ashx "></script>
<script language =" javascript "
          
src =" ajax/NAMESPACE.PAGECLASS,ASSEMBLYNAME.ashx "></script>
 
Where the bolded parts have the following meaning:
NAMESPACE.PAGECLASS
The namespace and class of the current page
(this will typically be the value of the Inherits attribute in the @Page directive)
ASSEMBLYNAME
The name of the assembly the current page is part of
(this will typically be the name of your project)
 
Bellow is a sample output for the sample.aspx page in an AjaxPlay project:
 
<%@ Page Inherits =" AjaxPlay.Sample" Codebehind="sample.aspx.cs" ... %>
<html>
 <head>
 <script language =" javascript " src =" ajax/common.ashx "></script>
 <script language =" javascript "
         
src =" ajax/AjaxPlay.Sample,AjaxPlay.ashx "></script>
 </head>
 <body>
    <form id =" Form1 " method =" post " runat =" server ">
      
...
    </form> 
 </body>
</html>
 
 
You can test that everything is working properly by manually navigating to the src paths in your browser (view source and copy and paste the paths). If both paths output some (seemingly) meaningless text, you’ve done well so far. If they’re outputting nothing or ASP.Net errors, something was improperly done.
 
Even if you don’t know how HttpHandlers work, the above should be understandable. Via the web.config, we’ve made sure that all requests that go to ajax /*.ashx are processed by the custom handler. Obviously, the two script tags will be processed by this custom handler.
 
We’ll now create a server-side function that’ll be asynchronously be available from a client-side call. Since not all return types are currently supported (don’t worry, upcoming versions will build on what’s currently there), we’ll stick with our simple ServerSideAdd functionality. In the code behind file, add the following method to your page class:
 
'VB.Net
<Ajax.AjaxMethod()> _
Public Function ServerSideAdd ( byval firstNumber As Integer , byval secondNumber
                                                
As Integer ) As Integer
  Return firstNumber + secondNumber
End Function
 
//C#
[Ajax.AjaxMethod()]
public int ServerSideAdd ( int firstNumber, int secondNumber)
{
 return firstNumber + secondNumber;
}
 
Note that the functions have the Ajax.AjaxMethod attribute set. The attribute serves to tell that wrapper to create JavaScript proxies for these methods so that they might be called client-side.
The last step is to call the function using JavaScript. The AJAX wrapper took care of creating a JavaScript function called Sample.ServerSideAdd function which takes two parameters. For the most basic functionality, all we need to do is call the method and pass two numbers:
 
<%@ Page Inherits =" AjaxPlay.Sample " Codebehind =" sample.aspx.cs " ... %>
<html>
 <head>
 <script language =" javascript " src =" ajax/common.ashx "></script>
 <script language =" javascript "
         
src =" ajax/AjaxPlay.Sample,AjaxPlay.ashx "></script>
 </head>
 <body>
    <form id =" Form1 " method =" post " runat =" server ">
      <script language ="javascript">
        var response = Sample.ServerSideAdd(100,99);
        alert (response.value);
      </script>
    </form> 
 </body>
</html>
 
Of course, we’ll want to use this powerful capability for more than simply alerting the user. That’s why all client-side proxies (such as the JavaScript Sample.ServerSideAdd function), also accept an additional property. The property is the callback function called in order to process the response:
 
Sample.ServerSideAdd(100,99, ServerSideAdd_CallBack);

function ServerSideAdd_CallBack(response){
  if (response.error != null){
   alert (response.error);
   return ;
 }
  alert (response.value);
}
 
We can see from the above code that we’ve specified an extra parameter.  ServerSideAdd_CallBack (also shown above) is the client-side function used to process the response from the server.  The callback function receives a response object which exposes three key properties:
 
value
The actual return value (be it a string, custom object or dataset) of the server-side function.
error
An error message, if any.
request
The raw response from the xml http request.
context
A context object.
 
 
First we check the error value to see if any errors occurred. You can easily play with the error property by throwing an exception in the server-side function. Then, in this simplified case, we alert the value. The request property can be used to get additional information (see box bellow).
 
To learn more about the Xml Http request, check out the following link dump:
 
The Ajax wrapper is capable of handling more than just the integer our ServerSideAdd function returned. It currently supports integers, strings, double, booleans, DateTime, DataSets and DataTables, as well as the primitive types of custom classes and arrays. All other types have their ToString values returned.
 
Returned DataSets work much like real .Net DataSet. Given a server side function which returns a DataSet, we could display the contents client side via:
 
<script language =" JavaScript ">
//Asynchronous call to the mythical "GetDataSet" server-side function
function getDataSet(){
 AjaxFunctions.GetDataSet(GetDataSet_callback);   
}
function GetDataSet_callback(response){
  var ds = response.value;
  if (ds != null && typeof (ds) == "object" && ds.Tables != null ){
  var s = new Array ();
 s[s.length] = " <table border=1> ";
  for ( var i=0; i<ds.Tables[0].Rows.length; i++){
   s[s.length] = " <tr> ";
   s[s.length] = " <td> " + ds.Tables[0].Rows[i].FirstName + " </td> ";
   s[s.length] = " <td> " + ds.Tables[0].Rows[i].Birthday + " </td> ";
   s[s.length] = " </tr> ";
 }
 s[s.length] = " </table> ";
 tableDisplay.innerHTML = s.join("");
 }
 else{
  alert (" Error. [3001] " + response.request.responseText);
 }
}
</script>
 
 
Ajax can also return custom classes. All that is required is that the class be marked with the Serializable attribute. Given the following class:
 
[Serializable()]
public class User{
  private int _userId;
  private string _firstName;
  private string _lastName;
 
  public int userId{
  get { return _userId; }
 }
  public string FirstName{
  get { return _firstName; }
 }
  public string LastName{
  get { return _lastName; }
 }
 
  public User( int _userId, string _firstName, string _lastName){
  this ._userId = _userId;
  this ._firstName = _firstName;
  this ._lastName = _lastName;
 }
  public User(){}
 
 [AjaxMethod()]
  public static User GetUser( int userId){
 //Replace this with a DB hit or something :)
  return new User(userId," Michael ", " Schwarz ");
 }
}
 
We would register the GetUser proxy via a call to the RegisterTypeForAjax:
 
private void Page_Load( object sender, EventArgs e){
 Utility.RegisterTypeForAjax( typeof (User));
}
 
Allowing us to asynchronously call the GetUser in client-side code with code such as:
 
 
<script language =" javascript ">
function getUser(userId){
 User.GetUser(GetUser_callback);
}
function GetUser_callback(response){
  if (response != null && response.value != null ){
  var user = response.value;
 if ( typeof (user) == "object"){         
   alert (user.FirstName + " " + user.LastName);
 }
 }
}
getUser(1);
</script>
 
The value returned in the response is actually an object which exposes the same properties as a server-side object ( FirstName, LastName and UserId).
 
As we’ve seen, the Ajax .Net wrapper is able to deal with many different .Net types. However, aside from a handful of .Net classes and the built-in types, the wrapper simply calls ToString() on anything it can’t properly return. To get around this, the Ajax .Net wrapper allows developers to create object converters which can be used to smoothly communicate complex objects between the server and the client. 
 
This guide will be updated with additional information on custom converters shortly (sorry).
 
In the above example, our server-side functions resided within the code behind of the executing page. However, there’s no reason why these functions can’t be in a separate class file. Remember, the way the wrapper works is to find all methods within the specified class that have the Ajax .AjaxMethod. The class in question is specified via the second script tag. Using Ajax.Utility.RegisterTypeForAjax we can specify any class we want. For example, it would be reasonable to keep our server-side functions in a separate class:
 
Public Class AjaxFunctions
 <Ajax.AjaxMethod()> _
  Public Function Validate(username As String, password As String) As Boolean
  'do something
 'Return something
  End Function
End Class
 
We could have the Ajax wrapper create proxies for this class by specifying this class’s type instead of the pages:
'Vb.Net
Private Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase .Load
 Ajax.Utility.RegisterTypeForAjax( GetType (AjaxFunctions))
 '...
End Sub
 
//C#
private void Page_Load( object sender, EventArgs e){
 Ajax.Utility.RegisterTypeForAjax( typeof (AjaxFunctions));
 //...
}
 
Remember, the client-side proxy takes the name of <ClassName>.<ServerSideFunctionName>. Therefore, if our ServerSideAdd function was located in the fictional AjaxFunctions class above, our client-side call would be: AjaxFunctions.ServerSideAdd(1,2)
The second script tag generated by the Ajax utility (or manually inserted by you) passes the namespace, class name and assembly of the page. Armed with this information, the Ajax.PageHandlerFactory is able to use reflection and get the details about any functions which have a certain attribute. Obviously, the handler looks for functions with the AjaxMethod attribute, gets their signature (return type, name, and parameters) and is thus able to create the necessary client-side proxy. Specifically, the wrapper creates a JavaScript object named the same name as your class which exposes the proxy. In other words, given a server-side class AjaxFunctions with an Ajax method ServerSideAdd, we should expect a JavaScript object named AjaxFunction which exposes a ServerSideAdd function. You can see this in action by pointing your browser to the path of the second script tag.
Ajax .Net wrapper is able to return Unicode characters from the server to the client. To do so, values must be html encoded on the server before being returned. For example:
 
[Ajax.AjaxMethod]
public string Test1( string name, string email, string comment){
  string html = "";
 html += " Hello " + name + " <br> ";
 html += " Thank you for your comment <b> ";
 html += System.Web.HttpUtility.HtmlEncode(comment);
 html += " </b>. ";
  return html;
}
 
It’s likely that you’ll need to access session information in your server side function. To do so, you must simply tell Ajax to enable such functionality via a parameter passed to the Ajax.AjaxMethod attribute. 
 
While looking at the session capabilities of the wrapper, let’s look at a couple other features. In this example, we have a document management system which puts a lock on a document while a user is editing it. Other users can request to be notified when the document because available.    Without AJAX, we’d need to wait until the user posted back in order to check if his or her queued documents were available. This is obviously not ideal. Using Ajax with session state support, this is quite easy.
 
First we’ll write our server side function, the goal of which is to loop through the documentIds the user wishes to edit (stored in a session) and return all released documents.
 
 
'Vb.Net
<Ajax.AjaxMethod(HttpSessionStateRequirement.Read)> _
Public Function DocumentReleased() As ArrayList
  If HttpContext.Current.Session("DocumentsWaiting") Is Nothing Then
  Return Nothing
  End If
  Dim readyDocuments As New ArrayList
  Dim documents() As Integer = CType(HttpContext.Current.Session("DocumentsWaiting"), Integer())
  For i As Integer = 0 To documents.Length - 1
  Dim document As Document = document.GetDocumentById(documents(i))
  If Not document Is Nothing AndAlso document.Status = DocumentStatus.Ready Then
   readyDocuments.Add(document)
  End If
 Next
  Return readyDocuments
End Function
 
 
//C#
[Ajax.AjaxMethod(HttpSessionStateRequirement.Read)]
public ArrayList DocumentReleased(){
  if (HttpContext.Current.Session[" DocumentsWaiting "] == null ){
  return null ;
 }
 ArrayList readyDocuments = new ArrayList();
  int [] documents = ( int [])HttpContext.Current.Session[" DocumentsWaiting "];
  for ( int i = 0; i < documents.Length; ++i){
 Document document = Document.GetDocumentById(documents[i]);
  if (document != null && document.Status == DocumentStatus.Ready){
    readyDocuments.Add(document);
 }        
 }
  return readyDocuments;
 }
}
 
Notice that we specify the HttpSessionStateRequirement.Read value (alternatives being Write and ReadWrite).
 
Now we write our JavaScript to take advantage of this method:
 
<script language =" javascript ">
function DocumentsReady_CallBack(response){
  if (response.error != null ){
  alert (response.error);
  return ;
 }
  if (response.value != null && response.value.length > 0){
  var div = document.getElementById("status");
 div.innerHTML = " The following documents are ready!<br /> ";
  for ( var i = 0; i < response.value.length; ++i){
   div.innerHTML += " <a href=/"edit.aspx?documentId= " + response.value[i].DocumentId + " /"> " + response.value[i].Name + " </a><br /> ";
 }      
 }
  setTimeout (' page.DocumentReleased(DocumentsReady_CallBack) ', 10000);
}
</script> 
<body onload ="setTimeout(' Document.DocumentReleased(DocumentsReady_CallBack)', 10000);">  
 
Our server side function is called once on page load and subsequently every 10 seconds. The call back function checks the response to see if any values were returned, and if so displays the newly available documents to the user in a div tag.
 
AJAX technology has already lead to sleek and rich web interfaces, previously reserved for desktop development. The Ajax .Net wrapper allows you to easily take advantage of this new power. Note that both the Ajax .Net wrapper and the documentation are under development. 
 
Keep a close eye on the AJAX .Net wrapper website:
For a good hands-on sample, check out the following demo application:
 

 

以下摘自翻译:

      就听说Ajax技术了,传说中是一种很强的东西,号称无刷新,其实是在web上通过javascript,使用异步的xmlhttp请求,实现无刷新的web界面。可惜一直没有体验过,先后听做PHP的朋友用过PHP的Ajax开发包,而且做了很多很酷的东西,使小生羡慕不已。

  今天下了一个.net Ajax开发包,该开发包包括ASP2.0和目前ASP1.1版使用的Ajax,详细地址参见http://ajax.schwarz-interactive.de/,接下来,开始。(下载请您点击:Ajax.dll

  1. 新建一个项目,在引用中添加引用Ajax.dll,Ajax.dll位于下载的压缩包里面。

  2.建立HttpHandler,在web.config里面加上

<configuration>
<system.web>
<httpHandlers>
<add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax" />
</httpHandlers>

<system.web>
</configuration>

      3.新建一个类DemoMethods,这个类实现获取客户端MAC地址:

using System;
using System.Web;

namespace AjaxSample
{
/** <summary>
/// Summary description for Methods.
/// </summary>
public class DemoMethods
{

[Ajax.AjaxMethod]
public string GetCustomerMac(string clientIP) //这里输入客户端IP,这个函数知识测试用,你也可以写一个其他的简单一点的函数代替
{
string mac = "";

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "nbtstat";
process.StartInfo.Arguments = "-a "+clientIP;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;

process.Start();

string output = process.StandardOutput.ReadToEnd();
int length = output.IndexOf("MAC Address = ");

if(length>0)
{
mac = output.Substring(length+14, 17);
}

process.WaitForExit();

return mac.Replace("-", "").Trim();
}
}

}

  4.写javascript,新建一个名为default.js文件如下

function GetMac()
{
var clientIP="192.168.0.1";
//document.getElementById("Mac").value=DemoMethods.GetCustomerMac(clientIP).value
alert(DemoMethods.GetCustomerMac(clientIP).value);
}

      5.在某个Aspx页面放上一个html 的button

  在页面上<head>中引用default.js :
<script language="javascript" src="default.js"></script>

  在INPUT的onclick事件中加上
οnclick="javascript:GetMac()"

<INPUT style="Z-INDEX: 101; LEFT: 392px; POSITION: absolute; TOP: 176px" type="button"

value="客户端获取IP" οnclick="javascript:GetMac();">

  6.在page页面的Page_Load事件中加上

private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
Ajax.Utility.RegisterTypeForAjax(typeof(AjaxSample.DemoMethods));
}

  注意:typeof(AjaxSample.DemoMethods)中,AjaxSample是命名空间,DemoMethods是要包含要调用方法的类,即上面第3步.新建类DemoMethods

  7.修改Global.asax的Application_Start事件,设置Ajax的HandlerPath :

protected void Application_Start(Object sender, EventArgs e)
{
Ajax.Utility.HandlerPath = "ajax";
}

  运行看看效果。是不是没有刷新就在服务器端取到客户端的MAC地址?

  需要注意的是:该版本的.net Ajax需要手工在中Global.asax加上Ajax.Utility.HandlerPath = "ajax"; 配置文件web.config必须加上HttpHandler的配置信息!

  该开发包的新版本还没有来得及体验,估计新版本中会方便一些,可能会去掉手动的设置Global.asax的Application_Start事件中加上Ajax.Utility.HandlerPath = "ajax";以及其他麻烦的设置!期待……

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值