AJAX在ASP.NET中的应用(三)——微软的AJAX_Extensions

      前言: “不只普通民众是傻瓜,软件开发工程师同样也是傻瓜”——微软的软件产品开发指导理念是路人皆知的,当初我踏入软件行业时由于没有洞悉微软的这个本质,导致现在已经是上了贼船难再下了。算了,既然微软已经把我当傻瓜看,如果我连傻瓜式的东西都用不熟,那就真成了傻瓜了。当然,说微软的东西都是傻瓜式的,有点“得了便宜反卖乖”的嫌疑,但从另一方面来考虑的话,就应该赞扬微软技术的简易实用,对于快速开发同时对性能要求不算苛刻的项目来说是非常好的选择。

      言归正传,ASP.NET在应用AJAX方面提供了一系列的服务器控件,如截图所示:

      这些控件的作用大致可以概括为(具体的用法会在后面一一介绍):
      ScriptManager:这是整个AJAX-Extensions的核心控件,也是整个ASP.NET的关键服务器控件。从该控件的名字可以看出,该控件用于管理最终呈现(术语:Render)页面中的脚本资源,也就是由它来添加和删除某些脚本。ScriptManager控件与静态类System.Web.UI. ScriptManager相互配合(如ScriptManager类使用最多的 RegisterClientScriptBlock、RegisterStartupScript等等注册脚本方法),能够灵活有效地控制最终呈现页面上的脚本。当然,ScriptManager核心作用还是在实现AJAX方面。需要注意的是:一个页面上只能存在最多一个ScriptManager控件。

    ScriptManagerProxy:这个控件是为了适用有母页面的情况。当母页面已经存在ScriptManager时,因为一个页面上只能存在最多一个ScriptManager控件,这样Content页面就不能存在一个独立的ScriptManager控件,而替代使用ScriptManagerProxy控件,然后通过它访问母版页的ScriptManager,作用相当于对母页面ScriptManager的代理。

     UpdatePanel:这个控件也是一个关键控件,该控件定义一个“相对独立的AJAX区域”,每个页面上可以存在任意个UpdatePanel控件,这些UpdatePanel之间可以通过其内部参数设置来决定是否相互影响。该控件具体的使用方法下面马上就会说明,总之,该控件创建一个更新AJAX的区域块,以及该区域块如何更新、何时更新、由谁来更新等等事项。

     Timer:这个控件功能单一,独立属性只有Interval(设定触发Tick事件的时间间隔,单位是毫秒),独立事件只有Tick(定时执行事件)。其作用在于定时执行Tick事件,PostBack回服务器。如果该控件是某个UpdatePanel的更新触发器,那么将引起该UpdatePanel的更新,否则将引起整个页面的重载(即重新走一遍页面周期)。

     UpdateProgress:与Timer控件地位相似,它也是个辅助控件。作用在于当该控件所在的UpdatePanel控件内已经PostBack之后,服务器返回结果之前的这段时间显示出来,而在未PostBack或服务器已经返回结果之后隐藏。目的在于提示用户:请求已经发送,正在处理。

      一,一个简单的使用ScriptManager和UpdatePanel来实现AJAX更新的实例:

     前台代码:

<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <asp:Button ID="aspbtn_trigger" runat="server" Text="点击我更新文本" OnClick="aspbtn_trigger_Click" />
        <asp:Label ID="asplbl_Context" runat="server" Text="这是原始文本"></asp:Label>
    </ContentTemplate>
</asp:UpdatePanel>

     后台代码:

protected void aspbtn_trigger_Click(object sender, EventArgs e)
{
    asplbl_Context.Text = "这是AJAX获取后的文本,用于测试使用UpdatePanel实现Ajax请求";
}

     运行页面可以发现,点击按钮后页面并没有刷新一遍,而只有文本更换而已,页面的其他部分完全没有变化。这就是实现Ajax请求的结果。

      二,UpdatePanel的比较详细的用法:

     注意!!:这里所说的“AJAX区域”就是由UpdatePanel控件内ContentTemplate子标签所包括的范围,这是一个Ajax更新的“相对独立块”

     UpdatePanel有以下几个重要的参数设置:

     1,UpdateMode属性:参数用于设定本AJAX区域的“更新时机”。UpdateMode有两中选项,Always和Conditional,其中Always表示只要页面任何AJAX区域内发生了PostBack事件,本AJAX区域都将更新,该设定为默认值;Conditional表示只有该AJAX区域内部的PostBack事件才引起的本AJAX区域的更新。注意:不属于任何AJAX区域内的PostBack事件因为会引起整个页面的重新载入,当然会引起各个AJAX区域的更新,但这种更新不是AJAX更新,本页面要讨论的是AJAX局部更新,切记!!

     2,RenderMode属性:这个参数功能很简单,用于设定本AJAX区域的样式堆积方式:“内联”还是“块状”。默认使用rendermode="Block",最终解析的AJAX区域用div标签(div为块状元素)包含;而使用rendermode="Inline"则最终解析的AJAX区域用span标签(span为内联元素)包含。

     3,ChildrenAsTriggers属性:该参数用于设定本AJAX区域的PostBack事件是否引起该区域的更新,该参数可以看成是当UpdateMode="Conditional"时,对本区域的更新时机设定起到进一步补充作用。默认为true,表示该区域内部的PostBack事件将引起本区域的更新。 但该参数设定为false时,要求UpdateMode="Conditional",否则页面会抛出异常。ASP.NET进行这样限定的原因在于,UpdateMode="Always"表示所有AJAX区域内的PostBack事件都引起区域的更新,这其中当然包括本区域内部的PostBack事件。因此ChildrenAsTriggers="false"与UpdateMode="Always"是不能同时存在的。

     4,AsyncPostBackTrigger子元素:这里设定元素(无论该参数是否位于UpdatePanel区域内)的PostBack事件,都会引起本区域的更新;包含两个参数:"ControlID":ASP.NET控件ID、"EventName":引起该控件PostBack的事件名称,如Click、TextChanged

     5,PostBackTrigger子元素:这里设定元素的所有的PostBack事件都将被本区域视为非AJAX请求而载入整个页面(注意:这里的元素可以为本AJAX区域内的,亦可以为其他区域(一般很少用到);设定为本区域较常见(如用到FileUpload控件上传附件的时候,触发PostBack元素一定要设为PostBackTrigger,否则文件会丢失))

      下面是对上面几个重要参数设置的示例:

      前台代码:

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<hr style="border: 3 double #987cb9" width="100%" color="#987cb9" size="3" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <p class="title">
            这是AJAX区域1,用于测试参数——UpdateMode,该参数用于设定本AJAX区域的“更新时机”。<br />
            UpdateMode有两中选项,Always和Conditional,其中Always表示只要页面任何AJAX区域内发生了PostBack事件,本AJAX区域都将更新,该设定为默认值;Conditional表示只有该AJAX区域内部的PostBack事件才引起的本AJAX区域的更新。<br />
            注意:不属于任何AJAX区域内的PostBack事件因为会引起整个页面的重新载入,当然会引起各个AJAX区域的更新,但这种更新不是AJAX更新,本页面要讨论的是AJAX局部更新,切记!!
        </p>
        <p>
            关键设置:UpdateMode="Conditional"
        </p>
        <asp:Button ID="aspbtn_trigger1" runat="server" Text="点击我将引起AJAX区域1的更新" OnClick="aspbtn_trigger1_Click" />
        <asp:Label ID="asplbl_Context1" runat="server" Text="这是AJAX区域1的原始文本"></asp:Label>
    </ContentTemplate>
</asp:UpdatePanel>
<hr style="border: 3 double #987cb9" width="100%" color="#987cb9" size="3" />
<asp:UpdatePanel ID="UpdatePanel2" runat="server" RenderMode="Inline">
    <ContentTemplate>
        <p class="title">
            这是AJAX区域2,用于测试RenderMode,该参数用于设定本AJAX区域的样式堆积方式:“内联”还是“块状”<br />
            默认使用rendermode="Block",最终解析的AJAX区域有div标签(div为块状元素)包含;而使用rendermode="Inline"则最终解析的AJAX区域有span标签(span为内联元素)包含。
            若查看最后生成的页面标签,可以看到区域最终生成<span id="UpdatePanel2">标签,而区域1生成 <div id="UpdatePanel1">
        </p>
        <p>
            关键设置:RenderMode="Inline"
        </p>
        <asp:Button ID="aspbtn_trigger2" runat="server" Text="这是非AJAX区域1内的按钮,点击我AJAX区域1内将无变化,虽然我调用的方法与aspbtn_trigger1按钮一致"
            OnClick="aspbtn_trigger1_Click" />
    </ContentTemplate>
</asp:UpdatePanel>
<hr style="border: 3 double #987cb9" width="100%" color="#987cb9" size="3" />
<asp:UpdatePanel ID="UpdatePanel3" runat="server" ChildrenAsTriggers="false" UpdateMode="Conditional">
    <ContentTemplate>
        <p class="title">
            这是AJAX区域3,用于测试ChildrenAsTriggers,该参数用于设定本AJAX区域的PostBack事件是否引起该区域的更新,该参数可以看成是当UpdateMode="Conditional"时,对本区域的更新时机设定起到进一步补充作用<br />
            默认为true,表示该区域内部的PostBack事件将引起本区域的更新。 但该参数设定为false时,要求UpdateMode="Conditional",否则页面会抛出异常。ASP.NET进行这样限定的原因在于,UpdateMode="Always"表示所有AJAX区域内的PostBack事件都引起区域的更新,这其中当然包括本区域内部的PostBack事件。因此ChildrenAsTriggers="false"与UpdateMode="Always"是不能同时存在的。
        </p>
        <p>
            关键设置:ChildrenAsTriggers="false" UpdateMode="Conditional"
        </p>
        <asp:Button ID="aspbtn_trigger3" runat="server" Text="虽然我位于区域3,但是点击我本区域的文本将不会更新"
            OnClick="aspbtn_trigger3_Click" />
        <asp:Label ID="asplbl_Context3" runat="server" Text="这是AJAX区域3的原始文本"></asp:Label>
    </ContentTemplate>
</asp:UpdatePanel>
<hr style="border: 3 double #987cb9" width="100%" color="#987cb9" size="3" />
<asp:UpdatePanel ID="UpdatePanel4" runat="server">
    <ContentTemplate>
        <p class="title">
            这是AJAX区域4,用于测试Triggers子元素,该元素用于设定本AJAX区域对特殊PostBack事件的“响应方式”,包含两种大类:<br />
            1,AsyncPostBackTrigger:这里设定元素(无论该参数是否位于UpdatePanel区域内)的PostBack事件,都会引起本区域的更新;包含两个参数:"ControlID":ASP.NET控件ID、"EventName":引起该控件PostBack的事件名称,如Click、TextChanged、</p>
        2,PostBackTrigger:这里设定元素的所有的PostBack事件都将被本区域视为非AJAX请求而载入整个页面(注意:这里的元素可以为本AJAX区域内的,亦可以为其他区域(一般很少用到);设定为本区域较常见(如用到FileUpload控件上传附件的时候,触发PostBack元素一定要设为PostBackTrigger,否则文件会丢失))
        <br />
        <p>
            关键设置:
            <asp:AsyncPostBackTrigger ControlID="aspbtn_outer1" EventName="Click" />
            <asp:PostBackTrigger ControlID="aspbtn_trigger4" />
        </p>
        <asp:Button ID="aspbtn_trigger4" runat="server" Text="虽然我位于AJAX区域4,但是点击我将引起整个页面的重载,而不是本区域的AJAX更新,原因在于PostBackTrigger中设定我非AJAX方式Postback"
            OnClick="aspbtn_outer1_Click" />
        <asp:Label ID="asplbl_Context4" runat="server" Text="这是AJAX区域4的原始文本"></asp:Label>
    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="aspbtn_outer1" EventName="Click" />
        <asp:PostBackTrigger ControlID="aspbtn_trigger4" />
    </Triggers>
</asp:UpdatePanel>
<hr style="border: 3 double #987cb9" width="100%" color="#987cb9" size="3" />
<p class="title">
    这是非AJAX区域</p>
<asp:Button ID="aspbtn_outer1" runat="server" Text="虽然我位于不属于任何一个AJAX区域,但是我能引起区域4的更新,且不刷新这个页面,因为在区域4的AsyncPostBackTrigger中设定了我作为其更新的发生器"
    OnClick="aspbtn_outer1_Click" />
</form>

    后台代码:

protected void aspbtn_trigger1_Click(object sender, EventArgs e)
{
    asplbl_Context1.Text = "这是AJAX获取后的文本,用于测试区域1内使用UpdatePanel实现Ajax请求,随机数:" + new Random().Next(100).ToString();
}
protected void aspbtn_trigger3_Click(object sender, EventArgs e)
{
    asplbl_Context3.Text = "这是AJAX获取后的文本,用于测试区域3内使用UpdatePanel实现Ajax请求,随机数:" + new Random().Next(100).ToString();
}
protected void aspbtn_outer1_Click(object sender, EventArgs e)
{
    asplbl_Context4.Text = "这是AJAX获取后的文本,用于测试区域4内使用UpdatePanel实现Ajax请求,随机数:" + new Random().Next(100).ToString();
}

      三,使用ScriptManager调用WebService实现AJAX请求:

     ScriptManager功能很强大,但许多设置因为几乎没有用过所以我在这里不敢说教了。这里只介绍如何调用Webservice。关于Webservice的基本知识假如读者还不具备的话,那么读者务必要先进行相关的了解才能有效地理解接下来的示例了。

     首先创建一个Webservice文件,位置为Resources/WebServiceForAJAX.asmx,代码如下:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class WebServiceForAJAX : System.Web.Services.WebService
{
    [WebMethod]
    public string GetString()
    {
        return "随机数" + new Random().Next(100).ToString();
    }
    [WebMethod]
    public int GetInt(int input)
    {
        return input + 100;
    }
    [WebMethod]
    public double GetDouble(double inputX, double inputY, double inputZ)
    {
        return inputX + inputY + inputZ;
    }
    [WebMethod]
    public double RuntimeError(string input)
    {
        return Convert.ToDouble(input);
    }
    [WebMethod]
    public double ThrowError(string input)
    {
        throw new ArgumentException("这里故意抛出异常,请忽视该异常!");
    }
}

     然后在页面中添加ScriptManager控件,并进行Webservice服务的引用,如下所示:

<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Services>
        <asp:ServiceReference Path="~/Resources/WebServiceForAJAX.asmx" />
    </Services>
</asp:ScriptManager>

     上面两步做好后就可以使用Javascript来直接调用。好吧,不得不承认的确是傻瓜化的。具体的用法如下:

      Javascript代码:

function CallWebService_None() {
    AJAX_Extensions.Resources.WebServiceForAJAX.GetString(SuccessHandle);
}
function CallWebService_One() {
    AJAX_Extensions.Resources.WebServiceForAJAX.GetInt(49, SuccessHandle);
}
function CallWebService_Multitude() {
    AJAX_Extensions.Resources.WebServiceForAJAX.GetDouble(0.111, 0.222, 0.333, SuccessHandle);
}
function CallWebService_Error() {
    //这里调用GetDouble方法,但是传入的参数都应该为double,这里故意将参数传入不能转换为double的字符串,前台JS获取异常后将转到异常处理方法。
    AJAX_Extensions.Resources.WebServiceForAJAX.GetDouble(0.111, 'NotANumber', 0.333, SuccessHandle, ErrorHandle);
}
function CallWebService_RuntimeError() {
    //这里调用的webservice方法传入参数符合要求,但是在方法内部试图将字符串转化为数字过程中抛出异常,前台JS获取异常后将转到异常处理方法。
    AJAX_Extensions.Resources.WebServiceForAJAX.RuntimeError('input', SuccessHandle, ErrorHandle);
}
function CallWebService_ThrowError() {
    //这里调用的webservice方法传入参数符合要求,但是在方法内部主动抛出异常,前台JS获取异常后将转到异常处理方法。
    AJAX_Extensions.Resources.WebServiceForAJAX.ThrowError('input', SuccessHandle, ErrorHandle);
}
function CallWebService_userContext() {
    var userContext = 0.111;
    AJAX_Extensions.Resources.WebServiceForAJAX.GetDouble(userContext, 0.222, 0.333,
    function(_returnval, userContext, addedParam1, addedParam2, addedParam3) {
        alert("返回值:" + _returnval + ",回调方法附加参数userContext:" + userContext + "、第一个额外参数addedParam1为被置为:" + addedParam1 + "、第二个额外参数addedParam2:" + addedParam2 + "、第三个额外参数addedParam3:" + addedParam3);
    }, null, userContext);
}
function SuccessHandle(_val) {      //成功回调方法
    alert("调用Webservice成功,返回结果为:" + _val.toString());
}
function ErrorHandle(_val) {        //异常回调方法
    alert("调用Webservice出错,错误信息:" + _val._message);   //这里讲异常提示信息用弹出框显示出来
}

      页面代码:

<input type="button" id="btn_trigger_none" value="点击我调用Webservice无参数方法" οnclick="CallWebService_None();" />
<input type="button" id="btn_trigger_one" value="点击我调用Webservice一个参数方法" οnclick="CallWebService_One();" />
<input type="button" id="btn_trigger_multitude" value="点击我调用Webservice多个参数方法" οnclick="CallWebService_Multitude();" />
<input type="button" id="btn_trigger_error" value="点击我调用Webservice出错处理" οnclick="CallWebService_Error();" />
<input type="button" id="btn_trigger_runtimeerror" value="点击我调用Webservice产生运行时错误"
    οnclick="CallWebService_RuntimeError();" />
<input type="button" id="btn_trigger_throwerror" value="点击我调用Webservice截取主动抛出的错误"
    οnclick="CallWebService_ThrowError();" />
<input type="button" id="btn_trigger_userContext" value="点击我调用Webservice使用userContext"
    οnclick="CallWebService_userContext();" />

     这里对ScriptManager调用Webservice总结如下:

      使用ScriptManager控件调用Webservice有以下几个条件:

        1,form元素存在,且runat设置为server
        2,ScriptManager控件存在
        3,子元素Services中要将该Webservice文件的地址包括进来,如 asp:ServiceReferencePath="~/Resources/WebServiceForAJAX.asmx"
        4,webservice类必须使用[System.Web.Script.Services.ScriptService]特性。
        5,被调用的方法必须使用 [WebMethod]特性
        6,被调用的方法必须为非静态方法,即不使用static关键字
      调用具体Webservice的方法注意事项:
        1,Webservice类在JS的对象为包括【命名空间+类名】,如在AJAX_Extensions.Resources.WebServiceForAJAX中AJAX_Extensions.Resources为命名空间,WebServiceForAJAX为Webservice类名
        2,JS调用Webservice方法传入的参数依次为【方法本身需要传入的参数(如果有,则必要)+成功回调方法(非必要)+异常回调方法(非必要)+回调函数额外的参数(非必要)】
           假如Webservice方法为public double GetDouble(doubleinputX, double inputY, double inputZ),则可以使用如下方法调用:AJAX_Extensions.Resources.WebServiceForAJAX.GetDouble(0.111,0.222,0.333, SuccessHandle, ErrorHandle,userContext);,
           其中“0.111,0.222,0.333”分别对应参数“doubleinputX, double inputY, double inputZ”;SuccessHandle为成功回调方法;ErrorHandle为异常回调方法;userContext为回调函数额外的参数
           几个概念——
                       成功回调方法:     当Webservice方法成功调用后执行的方法;
                       异常回调方法:      当Webservice方法调用出现异常后执行的方法;

                       回调函数额外的参数:成功回调方法和异常回调方法一般情况下参数都只有一个,当需要添加额外的参数数时,必须在“回调函数额外的参数(非必要)”中添加该参数,然后才能在回调方法中使用,否则所有传入的额外参数除第一个被置为Webservice方法名称外,其他参数都会被置为undefined


     四,UpdateProgress控件的使用实例:

      前台代码:

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <asp:Button ID="aspbtn_trigger1" runat="server" Text="点击我进行更新" OnClick="aspbtn_trigger1_Click" />
        <asp:Label ID="asplbl_Context1" runat="server" Text="这是原始文本"></asp:Label>
        <asp:UpdateProgress ID="UpdateProgress1" runat="server">
            <ProgressTemplate>
                <img src="Resources/ajax-loader.gif" />
            </ProgressTemplate>
        </asp:UpdateProgress>
    </ContentTemplate>
</asp:UpdatePanel>
</form>

      后台代码:

protected void aspbtn_trigger1_Click(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(2000);    //这里故意将线程处理时间延长2秒,以模拟服务器正在处理请求的阶段
    asplbl_Context1.Text = "这是AJAX获取后的文本,随机数:" + new Random().Next(100).ToString();
}

      可以看出,在点击按钮后,因为在后台System.Threading.Thread.Sleep(2000)估计将服务器响应延长2秒,在浏览器发出请求后,UpdateProgress中的内容就显示出来了,而在浏览器接收到响应后又消失了。因此可以得出结论:该控件作用是在服务器响应过程中显示,一般用于对用户的提示作用。

     五, Timer控件的使用实例:

      前台代码:

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <p>
            本区域将每个3秒进行一次自动更新,更新目标文本和当前时间
        </p>
        <asp:Literal ID="aspltl_CurrentTime" runat="server"></asp:Literal>
        <br />
        <asp:Label ID="asplbl_Context1" runat="server" Text="这是原始文本"></asp:Label>
        <asp:UpdateProgress ID="UpdateProgress1" runat="server">
            <ProgressTemplate>
                <img src="Resources/ajax-loader.gif" />
            </ProgressTemplate>
        </asp:UpdateProgress>
        <asp:Timer runat="server" Interval="3000" OnTick="Unnamed1_Tick">
        </asp:Timer>
    </ContentTemplate>
</asp:UpdatePanel>
</form>

      后台代码:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        aspltl_CurrentTime.Text = "当前时间:" + DateTime.Now.ToString();
    }
}
protected void Unnamed1_Tick(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(2000);    //这里故意将线程处理时间延长2秒,以模拟服务器正在处理请求的阶段
    asplbl_Context1.Text = "这是AJAX获取后的文本,随机数:" + new Random().Next(100).ToString();
    aspltl_CurrentTime.Text = "当前时间:" + DateTime.Now.ToString();
}

       这里是我为这篇文章配置的简单测试代码,点击下载

 


 






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值