您的位置:首页 > 理论基础 > 计算机网络

让UpdatePanel支持文件上传(5):支持页面重定向的HttpModule

2007-04-16 09:34 573 查看
我们现在试用一下这个组件。
  首先,我们将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我们现在试用一下这个组件。
  首先,我们将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|”。

  在客户端,我们可以找到下面的实现,它的作用是在收到页面重定向的信息之后跳转页面。请注意下方红色的代码:

客户端支持页面重定向的代码
___FCKpd___6


  明白了这点之后,我们也就能够轻松地编写一个这样的模块了:

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>


  现在,我们终于完成了所有的组件。您也不妨将其下载之后尝试一下吧,如果遇到了问题,请及时和我联系。:)

点击这里下载整个项目

English Version

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
___FCKpd___7


  上方红色的代码为我们的Module与ASP.NET AJAX中的ScriptModule之间唯一的区别。我们在web.config文件中注册了AjaxFileUploadModule之后,我们在服务器端调用Redirect方法之后,在客户端就能进行跳转了。此时客户端接收到的文本如下:

客户端收到的文本
___FCKpd___8


  现在,我们终于完成了所有的组件。您也不妨将其下载之后尝试一下吧,如果遇到了问题,请及时和我联系。:)

点击这里下载整个项目

English Version
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: