DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> AJAX入門 >> AJAX詳解 >> 讓UpdatePanel支持文件上傳(5):支持頁面重定向的HttpModule
讓UpdatePanel支持文件上傳(5):支持頁面重定向的HttpModule
編輯:AJAX詳解     

我們現在試用一下這個組件。

  首先,我們將AjaxUploadHelper控件放置在頁面中,緊跟在ScriptManager之後,因為AJaxUploadHelpe需要在第一時間告訴ScriptManager目前正處在一個異步刷新的過程中。

使用AJaxFileUploadHelper控件
<%@ Register Assembly="AJaxFileUploadHelper" Namespace="Jeffz.Web" TagPrefix="jeffz" %>

//...
<ASP:ScriptManager ID="ScriptManager1" runat="server" />
<jeffz:AJaxFileUploadHelper runat="server" ID="AJaxFileUploadHelper1" />
//...


  接著,在頁面上添加一個UpdatePanel,並在其中放置一個FileUpload控件,一個按鈕以及一個Label。為了更容易地看出異步刷新的效果,我們在頁面上添加兩個時間:

Page
<%= DateTime.Now %>
<ASP:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
        <%= DateTime.Now %><br />
        <ASP:FileUpload ID="FileUpload1" runat="server" />
        <ASP:Button ID="Button1" runat="server" Text="Upload" OnClick="Button1_Click" /><br />
        <ASP:Label ID="Label1" runat="server" Text=""></ASP:Label>
    </ContentTemplate>
</ASP:UpdatePanel>


  在Code Behind代碼中,我們為Button添加Event handler:

Code Behind
protected void Button1_Click(object sender, EventArgs e)
{
    if (this.FileUpload1.PostedFile != null)
    {
        this.Label1.Text = this.FileUpload1.PostedFile.ContentLength + " bytes";
    }
    else
    {
        this.Label1.Text = "";
    }
}


  打開頁面,我們可以看到頁面中顯示了那些控件和兩個時間。

  選擇一個文件並點擊Upload按鈕,我們可以發現只有UpdatePanel內部的時間被改變了,文件大小也顯示在了頁面上:


  很震撼吧?但是如果我們改變Code Behind中的代碼:

改變Code Behind中的代碼
protected void Button1_Click(object sender, EventArgs e)
{
    this.Response.Redirect("AnotherPage.ASPx", true);
}


  刷新頁面,點擊按鈕,您就會發現……失敗了?為什麼?

  原因如下:在一個“普通”的PostBack時,如果我們在執行了Redirect方法,浏覽器將會接受到一個Status Code為302的Response,以及一個跳轉目標。接著浏覽器就會將用戶帶去指定的目標頁面。當XHR發出的請求得到這樣一個Response之後,它將會自動重新請求而不會告訴客戶端究竟發生了什麼。這時,客戶端只能獲得目標跳轉之後的資源,而並非起初請求的資源。

  因此,ASP.Net AJax提供了一個組件來支持異步PostBack時的跳轉。這個組件就是ScriptModule,我們可以在web.config文件中找到它的注冊信息。

web.config文件的信息
<system.web>
    <!-- other configurations -->
    <httpModules>
        <add name="ScriptModule" 
	    type="System.Web.Handlers.ScriptModule, System.Web.Extensions, ..."/>
    </httpModules>
    <!-- other configurations -->
</system.web>
<!-- for IIS 7 -->
<system.webServer>
    <!-- other configurations -->
    <modules>
        <add name="ScriptModule" preCondition="integratedMode" 
	    type="System.Web.Handlers.ScriptModule, System.Web.Extensions, ..."/>
    </modules>
    <!-- other configurations -->
</system.webServer>


  下面的代碼片斷就是它解決這個問題的實現:

ScriptModule
public class ScriptModule : IHttpModule
{
    protected virtual void Init(HttpApplication context)
    {
        context.PreSendRequestHeaders += new EventHandler(PreSendRequestHeadersHandler);
        // ...
    }

    private void PreSendRequestHeadersHandler(object sender, EventArgs args)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpResponse response = application.Response;

        if (response.StatusCode == 302)
        {
            if (PageRequestManager.IsAsyncPostBackRequest(application.Request.Headers))
            {   
                string redirectLocation = response.RedirectLocation;

                List<HttpCookie> cookIEs = new List<HttpCookie>(response.CookIEs.Count);
                for (int i = 0; i < response.Cookies.Count; i++) {
                    cookies.Add(response.CookIEs[i]);
                }

                response.ClearContent();
                response.ClearHeaders();

                for (int i = 0; i < cookies.Count; i++)
                {
                    response.AppendCookie(cookIEs[i]);
                }

                response.Cache.SetCacheability(HttpCacheability.NoCache);
                response.ContentType = "text/plain";
                PageRequestManager.EncodeString(response.Output, "pageRedirect", 
                    String.Empty, redirectLocation);
            }
            else if //...
        }
    }
}


  我們響應了PreSendRequestHeaders事件,它將會在服務器端發送Header信息之前被觸發。此時,如果Status Code為302(表示Response將要使客戶端跳轉到另一個頁面去),則會清除所有即將發送的內容,並重新指定傳輸的信息。在這裡最重要的修改就是Response Body的內容。因為客戶端將要解析收到的字符串,因此我們必須發送格式為“length|type|id|content”。請注意上方紅色的代碼,它將會發送一段格式合法的字符串,例如“16|pageRedirect||/AnotherPage.ASPx|”。

  在客戶端,我們可以找到下面的實現,它的作用是在收到頁面重定向的信息之後跳轉頁面。請注意下方紅色的代碼:

客戶端支持頁面重定向的代碼
function Sys$WebForms$PageRequestManager$_onFormSubmitCompleted(sender, eventArgs)
{
    // ...

    for (var i = 0; i < delta.length; i++) {
        var deltaNode = delta[i];
        switch (deltaNode.type) {
            case "updatePanel":
                Array.add(updatePanelNodes, deltaNode);
                break;

	    // ...

            case "pageRedirect":
                window.location.href = deltaNode.content;
                return;
            //...
        }
    }

    // ...
}


  明白了這點之後,我們也就能夠輕松地編寫一個這樣的模塊了:

AJaxFileUploadModule
public class AJaxFileUploadModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.PreSendRequestHeaders += new EventHandler(PreSendRequestHeadersHandler);
    }

    private void PreSendRequestHeadersHandler(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpResponse response = application.Response;

        if (response.StatusCode == 302 && 
            AJaxFileUploadUtility.IsInIFrameAsyncPostBack(application.Request.Params))
        {
            string redirectLocation = response.RedirectLocation;
            List<HttpCookie> cookIEs = new List<HttpCookie>(response.CookIEs.Count);

            for (int i = 0; i < response.Cookies.Count; i++)
            {
                cookies.Add(response.CookIEs[i]);
            }

            response.ClearContent();
            response.ClearHeaders();

            for (int i = 0; i < cookies.Count; i++)
            {
                response.AppendCookie(cookIEs[i]);
            }

            response.Cache.SetCacheability(HttpCacheability.NoCache);
            response.ContentType = "text/plain";

            AjaxFileUploadUtility.WriteScriptBlock(response, true);
            
            StringBuilder sb = new StringBuilder();
            TextWriter writer = new StringWriter(sb);
            AjaxFileUploadUtility.EncodeString(writer, "pageRedirect", 
                String.Empty, redirectLocation);
            response.Write(sb.Replace("*/", "*//*").ToString());

            AJaxFileUploadUtility.WriteScriptBlock(response, false);

            response.End();
        }
    }

    public void Dispose() {}
}


  上方紅色的代碼為我們的Module與ASP.Net Ajax中的ScriptModule之間唯一的區別。我們在web.config文件中注冊了AJaxFileUploadModule之後,我們在服務器端調用Redirect方法之後,在客戶端就能進行跳轉了。此時客戶端接收到的文本如下:

客戶端收到的文本
<script type='text/Javascript' language='Javascript'>window.__f__=function()
    {/*16|pageRedirect||/AnotherPage.ASPx|*/}</script>


  現在,我們終於完成了所有的組件。

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved