随笔-26  评论-777  文章-0  trackbacks-55

摘要

      通过前两篇文章,我们知道使用了ASP.NET AJAX框架后,在JavaScript中调用后台WebService方法非常方便,几乎可以看做是“直接调用”。那么,这里引出了一个问题:调用方法就牵扯到参数的传递,而JavaScript和C#毕竟是两种不同的语言,数据类型怎么沟通?简单型数据类型还好说,如果我们需要的参数是个复杂类型呢?如分层架构中经常用到实体类做参数,我们在后台定义实体类类型,但是JavaScript可不知道这种定义,也没有相应数据类型,那么要如何解决这个问题呢?再进一步,如果需要的参数是个泛型集合呢?在JavaScript中又要如何表示这种类型?这一篇将解决这些问题。

 

先来看ASP.NET AJAX给你变个魔术

      我们都知道,使用分层架构开发系统时,使用实体类作为参数很很普遍的。那么如果我们需要调用的某个后台方法中需要实体类做参数,应该如何进行呢?毕竟C#中定义的实体类在JavaScript中可不认识啊。先不要着急,跟我做以下几步,我们一起来看个魔术。

      1.新建一个ASP.NET AJAX Enabled Web Site工程,并添加系统文件夹App_Code。

 

      2.我们在App_Code里新建一个C#类文件StudentInfo.cs,其内容如下:

StudentInfo.cs:

 1using System;
 2
 3[Serializable]
 4public class StudentInfo
 5{
 6    private string _name;
 7    private int _age;
 8    private string _college;
 9
10    public StudentInfo() { }
11
12    public string Name
13    {
14        get return this._name; }
15        set this._name = value; }
16    }

17
18    public int Age
19    {
20        get return this._age; }
21        set this._age = value; }
22    }

23
24    public string College
25    {
26        get return this._college; }
27        set this._college = value; }
28    }

29}

 

      这是一个典型的实体类,相信做过分层架构的朋友一定经常使用到类似的代码。这里要特别注意两点:一是这个类上面有一个[Serializeable]属性,这表明此类可以被序列化,另外就是这个类有一个空的构造函数。

 

      3.接着,我们在网站根目录下添加一个WebService:StudentService.asmx,其代码如下:

StudentService.cs:

 1using System;
 2using System.Web;
 3using System.Collections;
 4using System.Web.Services;
 5using System.Web.Services.Protocols;
 6using System.Web.Script.Services;
 7
 8[WebService(Namespace = "http://tempuri.org/")]
 9[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
10[ScriptService]
11[GenerateScriptType(typeof(StudentInfo))]
12public class StudentService : System.Web.Services.WebService
13{
14    public StudentService() { }
15
16    [WebMethod]
17    public string ShowStudentInfo(StudentInfo student)
18    {
19        return "学生姓名:" + student.Name + "<br />年龄:" + student.Age + "<br />所在院系:" + student.College;
20    }

21}

 

      ShowStudentInfo这个方法接收一个StudentInfo类型的参数,并根据这个实体类的信息组合成一段字符串返回。

 

      4.接着,在网站根目录下新建一个ajax.js文件,内容如下:

ajax.js:

 1function btnShowStudentInfo_onClick()
 2{
 3    var student=new StudentInfo();
 4    student.Name="张无忌";
 5    student.Age="20";
 6    student.College="计算机学院";
 7    
 8    StudentService.ShowStudentInfo(student,CallBackFunction);
 9}

10
11function CallBackFunction(responseText)
12{
13    $get("result").innerHTML=responseText;
14}

 

      这里我们大胆的直接初始化了一个StudentInfo,为什么说大胆呢?不要忘了,我们的StudentInfo类型可是在C#中定义的,JavaScript里可压根没有这个类型,当时我们这里却好像在写C#似的,不但初始化了这个类,还给其中成员赋值,并且当作参数传给了后台方法。这样能成功吗?我们接着看看吧。

 

      5.Default.aspx作为主页,我们添加如下内容:

Default.aspx:

 1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
 2
 3<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 4<html xmlns="http://www.w3.org/1999/xhtml">
 5<head runat="server">
 6    <title>复杂类型自动转换测试</title>
 7</head>
 8<body>
 9    <form id="form1" runat="server">
10        <asp:ScriptManager ID="ScriptManager1" runat="server">
11            <Scripts>
12                <asp:ScriptReference Path="~/ajax.js" />
13            
</Scripts>
14            <Services>
15                <asp:ServiceReference Path="~/StudentService.asmx" />
16            </Services>
17        </asp:ScriptManager>
18        <div>
19            <input id="btnShowStudentInfo" type="button" value="ShowStudentInfo" onclick="btnShowStudentInfo_onClick()" />
20            <div id="result"></div>
21        </div>
22    </form>
23</body>
24</html>

 

      这里就不用做过多解释了,看过前两篇的朋友肯定很容易就明白这段代码是什么意思。运行后,我们单击按钮,得到如下效果:

 

 

 

      可以看到,不仅程序运行没有报错,而且我们在JavaScript中定义的实体类被传到后台,并神奇的变成了C#实体类,作为参数完成了数据传递工作。运行结果非常令人满意。

 

魔术揭秘

      在上面的例子中,我们没有在JavaScript定义StudentInfo,更没有写代码把JavaScript实体类转换成C#实体类,但是程序正确执行了。很显然,有人替我们做了这一切,那是谁呢?当然是我们亲爱的ASP.NET AJAX。这就是这个框架另一项神奇的功能:前后台间数据类型自动转换,这个转换可不仅包括简单类型,还包括像实体类这样的复杂类型。那么,其工作原理是什么呢?

      仔细看StudentService.cs的代码,在类定义的上面,有一个[GenerateScriptTyep(typeof(StudentInfo))] 属性,秘诀就在这里。当我们给WebService类加上这条属性时,ASP.NET AJAX会在运行时自动为我们生成一个JavaScript版本的StudentInfo类,这个类的所有属性都和C#版的一模一样。所以,我们在JavaScript中实例化并赋值的其实是一个JavaScript版的StudentInfo。而后,当我们调用ShowStudentInfo方法时,ASP.NET AJAX框架会自动将JavaScript版的StudentInfo序列化成JOSN字符串,然后传到后台,后台再将这段字符串反序列化成C#版的StudentInfo,并作为参数传递给ShowStudentInfo,从而顺利完成工作。

      当然,如果某个后台方法返回一个StudentInfo类型的返回值,它也可以准确无误从C#传到JavaScript中。也就是说,序列化和反序列化都是双向的。

 

自动转换的条件

      知道了上述原理,那么如何才能自动转换呢?或者说具备什么条件的复杂类型才可以自动转换呢?大约有以下几点:

      1.需要在WebService中使用[GenerateScriptTyep()]属性指明要自动生成的复杂数据类型。

      2.该复杂类型必须有一个无参数的构造函数。

      3.该复杂类型的所有公有属性必须有get和set方法。

      另外值得注意的是,生成的JavaScript版本类只包含原类的公有属性,而私有属性和方法是不会映射过来的。应该说,这个技术对使用分层架构的应用特别有用,因为可以直接在客户端使用服务器端的实体类进行数据传输。

 

ASP.NET AJAX到底能自动转换哪些数据类型?

      1.基本类型将被转换为基本类型。如整形、浮点型、字符串、布尔型、DateTime等。(全自动转换)

      2.枚举类型将被转换为枚举类型。(全自动转换)

      3.复杂类型将转换为同名复杂类型,但只保留公有属性。(需要使用[GenerateScriptTyep(typeof(TypeName))]属性声明)

      4.数组、泛型集合将转换为数组。(全自动转换)

      5.DataTable将转换为JavaScript版的DataTable,但是需要ASP.NET Futures CTP的支持。

 

结束语

      这一篇中介绍了ASP.NET AJAX中非常有用的一个特性:数据类型自动转换。通过这个功能,使得前台可以更方便的调用后台程序。尤其是使用实体类传递数据会变得非常方便。在下一篇中,将介绍客户端组件的概念、使用客户端组件思想进行JavaScript开发以及简化的DOM操作。

      本文用到的实例可以在这里下载:AutoConvertionTest.rar

 

主要参考文献

      [1] 陈黎夫,ASP.NET AJAX程序设计-第II卷:客户端,人民邮电出版社,2007年10月

posted on 2008-07-24 00:07 T2噬菌体 阅读(1572) 评论(26)  编辑 收藏 所属分类: .NETAjaxWeb Development

评论:
#1楼  2008-07-24 00:26 | Bēniaǒ      
可以直接返回对象类型的.
你是使用的客户端生成的代理来建立的客户端StudentInfo对象.

可以看看我的这篇,和你这篇差不多,在客户端代理上稍微介绍得详细些.
http://www.cnblogs.com/beniao/archive/2008/04/29/1173695.html
  回复  引用  查看    
#2楼  2008-07-24 00:29 | Apple Yang      
我都晕哦
刚登陆一下就把我的沙发抢了。

我开始关注楼主的文章了,谢谢楼主。
  回复  引用  查看    
#3楼 [楼主] 2008-07-24 00:32 | T2噬菌体      
@Bēniaǒ
你的文章相当精细啊,呵呵,比我的详细多了。
  回复  引用  查看    
#4楼 [楼主] 2008-07-24 00:33 | T2噬菌体      
@Apple Yang
呵呵,一起学习!!!

  回复  引用  查看    
#5楼  2008-07-24 01:36 | Bēniaǒ      
@Apple Yang
呵呵,我占了SF,你就坐板凳吧.下次不和你抢了.
  回复  引用  查看    
#6楼  2008-07-24 08:48 | datetime [未注册用户]
楼主试过DateTime类型吗?
  回复  引用    
#7楼  2008-07-24 09:37 | Tony Zhou      
good!
  回复  引用  查看    
#8楼  2008-07-24 10:39 | datasky      
写得非常不错!
楼主的文章很实用,不像有些人的文章很空洞,纯粹忽悠人!
更新速度也相当快!
关注你的下一篇!
  回复  引用  查看    
#9楼  2008-07-24 11:11 | 9ago [未注册用户]
login.js 文件是一个用 ext 构造的一个登陆框

login.aspx.cs 这个我以前 没有ext做登陆时,写的登陆事件处理 ,

现在我login.aspx 页面的控件 都删了, 直接采用 用extjs 做的登录框 登陆


我的后台事件 login.aspx.cs 文件 要怎么该 才能接受到 extjs 做的登录框的参数


怎样调用 login.aspx.cs 文件里的 button 按钮事件 进行身份验证


非常感谢!!

  回复  引用    
#10楼 [楼主] 2008-07-24 11:13 | T2噬菌体      
@datetime
试过。怎么了?

  回复  引用  查看    
#11楼 [楼主] 2008-07-24 11:18 | T2噬菌体      
@9ago
可不可以再简要说一下你的意思,我不太明白

  回复  引用  查看    
#12楼  2008-07-24 11:22 | mouser [未注册用户]
DateTime类型有问题吗? 我在WebService给DateTime类型的属性个Now
JS显示出来这个样子:Thu Jul 24 11:09:13 UTC+0800 2008

请教博主,我直接安装的VS2008
是不是只安装了核心部分,还要另外安装ASP.NET Futures CTP吧。
不过好像 只能下到 ASPNETFutures.msi ,体积变大了,是一个东西吧。
Thanks



  回复  引用    
#13楼 [楼主] 2008-07-24 11:41 | T2噬菌体      
@mouser
JavaScript的Date类型默认就是那样子的,需要别的格式需要自己格式化。你可以查一下Date对象的format方法和localFormat方法,这两个方法和格式化有关。具体格式化字符及详细介绍请参考MSDN的:
http://msdn2.microsoft.com/en-us/library/bb79761a-ca08-44ee-b142-b06b3e2fc22b.aspx

我没安装过VS2008,不知08有没有自动安装ASP.NET Futures CTP。应该就是ASPNETFutures.msi吧。

  回复  引用  查看    
#14楼  2008-07-24 12:24 | Henllyee Cui      
@T2噬菌体
DateTime类型不会序列化成jason的。而DataTable为什么不能序列化,因为设计到了循环引用的问题,对于循环引用的问题我们可以通过自定义JavascriptConvert来实现
  回复  引用  查看    
#15楼 [楼主] 2008-07-24 12:31 | T2噬菌体      
@Henllyee Cui
恩,一般来说DataTable需要自定义JavascriptConvert,不过ASP.NET Futures CTP有自带的DataTable的转换方案。

DateTime类型有没有序列化我不知道,不过自动转换是没问题的。
  回复  引用  查看    
#16楼  2008-07-24 15:15 | xland      
顶一个
  回复  引用  查看    
#17楼  2008-07-24 17:07 | 搞IT的狐狸      
恩恩 继续整理ING
  回复  引用  查看    
#18楼  2008-07-24 17:08 | 搞IT的狐狸      
另外楼猪 觉得 目前.NET AJAX 和 下一代 技术 WPF/E 啥的 有何对比性?
  回复  引用  查看    
#19楼 [楼主] 2008-07-24 17:30 | T2噬菌体      
@搞IT的狐狸
对WPF没研究啊,只知道个概念……

  回复  引用  查看    
#20楼  2008-07-25 15:45 | Duron800 [未注册用户]
把代码放到VS 2008里,[GenerateScriptTyep(typeof(StudentInfo))] 好像没有也可以。
  回复  引用    
#21楼 [楼主] 2008-07-25 15:50 | T2噬菌体      
@Duron800
其实在VS2005里没有也可以,不过最好加上

  回复  引用  查看    
#22楼  2008-07-25 16:05 | Duron800 [未注册用户]
不太明白,为什么没有也行?
  回复  引用    
#23楼  2008-07-25 16:13 | Duron800 [未注册用户]
也就是加不加那个标记都会产生代理类?
  回复  引用    
#24楼 [楼主] 2008-07-25 16:29 | T2噬菌体      
@Duron800
我还是解释一下吧:
对于某个方法参数中或者返回值中出现过的复杂类型,是可以不用加属性标记的,框架会自动生成。
但是如果是内嵌的,也就是没有出现在参数中或者返回值中的复杂类型一定需要加属性标记。
但是为了保险起见,我建议都加上那个属性标记。

  回复  引用  查看    
#25楼  2008-07-25 16:30 | Duron800 [未注册用户]
@T2噬菌体
明白了,谢谢。
  回复  引用    
#26楼  2008-08-13 11:41 | ABS [未注册用户]
该复杂类型的所有公有属性必须有get和set方法?怎么理解?
  回复  引用    

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交