探讨微软ASP.NET AJAX控件开发技术(服务器端)

作者:网络 来源:佚名 更新时间:2008-11-07 01:53:53 点击:

  一、简介

  到目前为止,我们已经讨论了开发ajax控件所涉及的客户端相关技术。现在,让我们来讨论此过程中与服务器端相关的一些技术。

  需要说明的是,在【客户端】篇中我们的举例本质上仅是使用asp.net ajax框架提供的面向对象javascript技术来增强了一个客户端图像组件,而没有明显涉及到ajax技术(除了scriptmanager在后台以ajax方式下载并管理客户端脚本代码外)。所以,这个例子是简单的,仅凭客户端相关知识就可以使用这个增强控件。

  但是,在实际开发中,当要增强的客户端控件涉及到ajax技术时,或者干脆是想增强服务器端组件(如updatepanel控件)时,我们必须进行相关的服务器端编程,而这要求我们必须对ajax控件开发中所涉及的服务器端相关联的类有所了解。而且,还要以asp.net 2.0服务器控件开发相关知识为基本前提,特别是在开发复杂的ajax控件时。

  在本篇中,我们要重新构造一个增强的图像按钮控件mysrvimagebutton,此控件将以asp.net 2.0服务器控件imagebutton为基础。

  二、ajax控件开发服务器端相关技术

  首先,让我们来看一下ajax控件开发服务器端相关组件及其关系,这些类之间的继承关系图如下图1所示。

  探讨微软asp.net ajax控件开发技术(服务器端)

  图1:控件开发涉及的主要服务器端类之间层次结构图

  上图展示了组件、控件和扩展器之间的继承关系。如你所见,为了开发一个控件(注意,component和extender不在本文讨论范围之内),我们有两个选择:其一,创建一个派生自scriptcontrol的类;其二,创建一个实现iscriptcontrol接口的类。但是,如果你想使你的控件从webcontrol派生,那么,scriptcontrol应该是一个更好的选择—因为它正是派生自webcontrol控件本身。但是,如果你想从头开发创建你的控件,并且不要求实现webcontrol所具备的任何内在特征,那么,实现iscriptcontrol则更为恰当。此外,当你想在一个现有控件(例如本文中的mysrvimagebutton)中添加ajax特征时选择使用接口iscriptcontrol也会是你的选择。但是这两种方法都要求重载下列两个方法:①、getscriptdescriptors;②、getscriptreferences。

  • 本文来源于网页设计爱好者web开发社区http://www.html.org.cn收集整理,欢迎访问。
  • |||

      三、getscriptdescriptors

      这个方法负责在客户端以自动方式生成$create语句(而在上篇中是使用手工方式)。它使用了一个特殊类scriptdescriptor来生成它。在继续往下讨论前,首先让我们来浏览一下scriptdescriptor类中的继承层次图(如图2所示):

      探讨微软asp.net ajax控件开发技术(服务器端)

      图2:scriptdescriptor类中的继承层次图

      显然,每一种具体类型的组件都存在其单独的描述符。如果你在开发一个常规组件,那么,这个方法会返回一个scriptcomponentdescriptor的实例。对于扩展器而言,该方法返回的是一个scriptbehaviordescriptor实例;而对于一个控件,则返回scriptcontroldescriptor类的实例。该描述符中提供了一些特定的方法用于创建服务器端与客户端的“连接”。下面,还是让我们来分析一个有关$create语句是如何在服务器端“注入”的简短示例:

    //上篇中从客户端以手工方式使用$create
    $create(ajaximagebuttonnamespace.mycliimagebutton,
    {'hoverimageurl':'images/updateh.gif'},
    {'click':buttonclicked}, null, $get('clibtn'));
    在本文中,我们在服务器端以下列几个语句共同自动生成$create语句:
    scriptcontroldescriptor desc =
    new scriptcontroldescriptor("ajaximagebuttonlib.mysrvimagebutton",
    clientid);
    if (!string.isnullorempty(hoverimageurl))
    {
    desc.addproperty("hoverimageurl", hoverimageurl);
    }
    if (!string.isnullorempty(clientclickfunction))
    {
    desc.addevent("click", clientclickfunction);
    }
    return desc;

      在上面的代码中,我们在构造器中传递客户端类型(尽管客户端和服务器端具有相同的类型名)和dom元素id。这一步将填充$create语句的第一个和最后一个参数。此后,我们设置hoverimageurl属性,它对应于$create语句的属性部分。最后,通过设置click事件处理器,我们填充$create语句的事件部分。下面是脚本描述符中暴露的几个重要的方法:

  • 本文来源于网页设计爱好者web开发社区http://www.html.org.cn收集整理,欢迎访问。
  • |||

      1)addproperty()

      这个方法能够在客户端添加一个属性。第一个参数相应于属性名,第二个参数对应该参数的取值。

      2)addevent()

      这个方法在客户端添加一个事件。第一个参数相应于事件名,第二个参数对应你想绑定的函数的名称。

      3)addscriptproperty()

      这个方法能够把javascript代码指定为属性的一个值。对于复杂的属性赋值通常都要求这样的操作。

      4)addelementproperty()

      这个方法在客户端添加一个属性,但是其与addproperty方法间的区别在于,该值作为一个参数传递给$get方法。

      5)addcomponentproperty()

      这个方法负责在$create语句的component部分添加一个组件引用。该值将被用于$find语句中实现属性的赋值。这个方法的第一个参数相应于属性名,第二个参数对应该组件的id。

      四、getscriptreferences

      这个方法负责在scriptmanager中注册javascript文件。在这个方法中,针对每一个要求的javascript文件,我们都需要创建一个相应的scriptreference实例。例如,在图像按钮例子中,我们按如下方式注册javascript文件:

    ienumerable<scriptreference> iscriptcontrol.getscriptreferences()
    {
    return new scriptreference(page.resolveurl("~/srvimagebutton.js"));
    }

      此外,我们还可以以嵌入式资源方式注册javascript文件。为此,我们必须首先在visual studio的解决方案资源管理器中把一个javascript文件标记为一种嵌入式资源。然后,我们必须添加上webresource属性以便利用asp.net 2.0 web资源处理器。下列代码展示了如何把一个javascript文件注册为一个嵌入式资源:

    [assembly: webresource("mycontrols.subcontrol.script1.js", "text/javascript")]
    namespace mycontrols{
    public class subcontrol: control, iscriptcontrol
    {
    //………
    ienumerable<scriptreference> iscriptcontrol.getscriptreferences()
    {
    return new
    scriptreference(this.page.clientscript.getwebresourceurl(
    this.gettype(), "mycontrols.subcontrol.script1.js"));
    }
    }
    }

      此外,如果我们想实现iscriptcontrol接口而不是从scriptcontrol中继承的话,我们还必须重载onprerender与render方法。这样将能确保scriptmanger识别出该服务器控件是一个支持ajax功能的控件。


    |||

      下列代码展示了开发基于asp.net 2.0服务器端控件的ajax控件时必须在服务器端实现的最少代码:

    using system;
    using system.collections.generic;
    using system.web;
    using system.web.ui;
    using system.web.ui.webcontrols;
    namespace dummynamespace
    {
    public class dummycontrol : control, iscriptcontrol
    {
    public dummycontrol(): base()
    {}
    protected override void onprerender(eventargs e)
    {
    base.onprerender(e);
    scriptmanager scriptmanager = scriptmanager.getcurrent(page);
    if (scriptmanager == null)
    {
    throw new invalidoperationexception(
    "此页面中必须存在一个scriptmanager控件!");
    }
    scriptmanager.registerscriptcontrol(this);
    }
    protected override void render(htmltextwriter writer)
    {
    base.render(writer);
    writer.addattribute(htmltextwriterattribute.id, this.clientid);
    writer.renderbegintag(htmltextwritertag.div);
    writer.write("这是一个哑元控件");
    writer.renderendtag();
    if (!designmode) {
    scriptmanager.getcurrent(this.page).registerscriptdescriptors(this);
    }
    }
    ienumerable<scriptdescriptor> iscriptcontrol.getscriptdescriptors()
    {
    //因为这仅是一个哑元控件,所以我们只是创建一个新的实例
    return new scriptcontroldescriptor("dummynamespace.dummycontrol", clientid);
    }
    ienumerable<scriptreference> iscriptcontrol.getscriptreferences()
    {
    return new scriptreference(page.resolveurl("~/dummycontrol.js"));
    }
    }
    }

      上面代码中,我们在onprerender方法中实现注册控件,而在render方法中注册脚本描述符部分。当然,如果页面上不存在scriptmanager控件的话,我们必须抛出一个错误提示。但是,如果你正在开发非基于asp.netajax框架的控件的话,你完全可以从页面中删除scriptmanager控件。

  • 本文来源于网页设计爱好者web开发社区http://www.html.org.cn收集整理,欢迎访问。
  • |||

      五、创建基于asp.net服务器端控件的增强ajax图像控件

      (一)创建示例ajax网站

      启动visual studio 2005,选择“文件→新建网站…”,然后选择“asp.net ajax-enabled web site”模板,命名工程为“ajaxservctrltest”,并选择c#作为内置支持语言,最后点击“确定”。

      (二)创建ajax技术支持的增强服务器控件

      点击菜单“文件→添加→新建项目…”,在“添加新项目”对话框中,从左边选择“项目类型”为“visual c#→windows”,从右边选择“模板类型”为“web控件库”,输入控件库的名字为ajaximagebuttonlib,选择目标目录为前面创建的网站根目录,最后点击“确定”。

      接下来,根据我们前面的分析,把类库源webcustomcontrol1.cs文件的内容更改为以下形式:

    //…………(省略命名空间引用部分)
    namespace ajaximagebuttonlib
    {
    public class mysrvimagebutton :
    system.web.ui.webcontrols.imagebutton, iscriptcontrol
    {
    public string hoverimageurl
    {
    get
    {
    object value = viewstate["hoverimageurl"];
    return (value == null) ? string.empty : (string)value;
    }
    set
    {
    viewstate["hoverimageurl"] = value;
    }
    }
    public string clientclickfunction
    {
    get
    {
    object value = viewstate["clientclickfunction"];
    return (value == null) ? string.empty : (string)value;
    }
    set
    {
    viewstate["clientclickfunction"] = value;
    }
    }
    public mysrvimagebutton()
    : base()
    {
    }
    protected override void onprerender(eventargs e)
    {
    base.onprerender(e);
    scriptmanager scriptmanager = scriptmanager.getcurrent(page);
    if (scriptmanager == null)
    {
    throw new invalidoperationexception
    ("scriptmanager required on the page.");
    }
    scriptmanager.registerscriptcontrol(this);
    }
    protected override void render(htmltextwriter writer)
    {
    base.render(writer);
    if (!designmode)
    {
    scriptmanager.getcurrent(this.page).registerscriptdescriptors(this);
    }
    }
    ienumerable<scriptdescriptor> iscriptcontrol.getscriptdescriptors()
    {
    scriptcontroldescriptor desc =
    new scriptcontroldescriptor("ajaximagebuttonlib.mysrvimagebutton", clientid);
    if (!string.isnullorempty(hoverimageurl))
    {
    desc.addproperty("hoverimageurl", hoverimageurl);
    }
    if (!string.isnullorempty(clientclickfunction))
    {
    desc.addevent("click", clientclickfunction);
    }
    yield return desc;
    }
    ienumerable<scriptreference> iscriptcontrol.getscriptreferences()
    {
    yield return new scriptreference(page.resolveurl("~/srvimagebutton.js"));
    }
    }
    }

      首先,我们注意到我们要创建的新控件mysrvimagebutton继承自asp.net服务器控件imagebutton,并继承了接口iscriptcontrol。


    |||

      有了前面的理论描述,在此,我们省略对于其中几个常规方法的描述。

      接下来,我们要构建这个控件库(即程序集)。右击此库工程,并点击“生成”命令以生成程序集ajaximagebuttonlib.dll,此库文件中即包含了我们的服务器控件。

      (三)创建客户端javascript代码

      这里创建的客户端控件类相应的javascript文件imagebutton.js在内容上完全相同,只不过为了区别起见,我们进行了某些地方的重新命名罢了。在此不再赘述。

      (四)在示例网页中应用构建的新控件

      以鼠标右击前面网站ajaxservctrltest,把它设置为“启动项目”。事实上,因为这个网站工程与前面的类库工程创建于同一个方案下,所以,在前面生成程序集ajaximagebuttonlib.dll的一结束,新建的服务器控件就被自动添加到visual studio 2005工具栏中,如下图3所示。于是,我们可以直接把这个控件拖动到示例网页default.aspx中。

      探讨微软asp.net ajax控件开发技术(服务器端)

      图3:拖动新建的服务器控件到示例网页中

      根据前面的控件代码实现,不出所料,点击上图3中的图形按钮控件,即可在其相应的“属性”对话框中设置这个控件的hoverimageurl属性,而且指定其clientclickfunction方法(其实正是此控件的click事件处理器函数指针)。

      注意,因为控件代码中的方法getscriptreferences已经为我们自动生成了前面提到的$create方法,所以我们不需要再在scriptmanager中注册在本篇中创建的javascript文件—srvimagebutton.js了。

      (五)运行及性能简析

    商业源码热门下载www.html.org.cn

    |||

      现在,请按f5键运行此页面并移动鼠标到图像按钮上观察,你会注意到结果与上篇中的效果一致(即在鼠标移动切换新图像时,这些动作都发生于客户浏览器端而不再与服务器端相关)。下图4相应于此示例页面运行时刻快照。

      探讨微软asp.net ajax控件开发技术(服务器端)

      图4:示例网页运行时刻屏幕快照

      通过以鼠标右击网页并选择弹出菜单中的“查看源文件”观察上、下篇中示例页面相应的源码,我们会注意到其内容基本是一致的。另外,通过使用fiddler观察这两个示例页面下载到客户端时各模块的大小,你也会注意到基本一致,如下面图5所示。

      探讨微软asp.net ajax控件开发技术(服务器端)

      图5:两个示例页面下载到客户端时各模块大小比较

      因为本文两个例子极为简单,所以其性能基本平衡。但随着服务端编程的复杂化,本篇中基于服务器端控件的扩展方案应该有较大的性能损耗。但应该仍具有令人满意的效果,这也正是ajax control toolkit控件数量急剧增加的重要原因之一。而上篇中的方案基于“纯粹”(相对而言)的客户端,即使性能上与本篇中方案相差无几,但是却明显多出了跨越服务器端平台的优势,这也正是上篇中方案吸引人的主要原因。

      六、总结

      虽然以上、下两个篇幅形成此文,但是这也仅能通过简短的例子向你阐述了开发asp.netajax框架中的ajax控件所涉及的主要技术。尽管目前的asp.net ajax框架已经形成正规的1.0版本,而且这个框架为基于ajax技术开发以asp.net 2.0为主的web应用提供了全方位支持,但是这个框架仍然在许多方面有待改进。事实上,我们可以进一步沿着asp.net ajax客户端与服务器端架构层次关系图进一步扩展其底层。当然,在此框架与visual studio整合方面也存在相当的挖掘潜力。

      如今,随着微软silverlight技术的推出,asp.net ajax框架的重要性日显突出。自然,与此框架相关的控件开发也必将在这一大环境中占居着重要的位置。